webForumDet fria alternativet

nhibernate + generic dao

.NET

27 svar · 1 232 visningar · startad av doggelito

Medlem sedan juni 20003 076 inlägg
Frågan#1

jag skulle behöva plugga på lite om generics i dao sammanhang men får inte fram nån vettig googling.
det jag vill uppnå är att kunna ha 1 dao-interface som innehåller mina dao:s.
allt är sedan mappat genom nhibernate.
sen vill jag kunna skicka in ex. en produktklass in i interfacet för att spara den i databasen.

jag har sett vissa exempel på detta men det är så svårt att förstå när man bara skrollar radvis med kod.

nån som läst nån bra artikel eller så om detta? :D

Medlem sedan dec. 19996 522 inlägg
#2

Du vill alltså få fram en typ av ActiveRecord-tänk? Isåfall är ActiveRecord fårn CastleRecord kanske ett alternativ. Annars bör det väll inte vara så svårt att göra ett generiskt dao utan den hårda kopplingen mellan domän och persistent som AR skapar.

public interface IGenericDao<T> : IDisposable
{
        /// <summary>
        /// Gets an object by id
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        T GetObjectById(Guid Id);

        /// <summary>
        /// Saves a new object
        /// </summary>
        /// <param name="objectToSave"></param>
        /// <returns></returns>
        T SaveNewObject(T objectToSave);
 }
  public class NHibernateGenericDao<T> : NHibernateDaoBase, IGenericDao<T>
	{
        /// <summary>
        /// Gets an object by Id
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public T GetObjectById(Guid Id)
        {
            try
            {
                ICriteria criteria = Session.CreateCriteria(typeof(T));
                criteria.Add(Expression.Eq("Id", Id));
                return criteria.UniqueResult<T>();
            }
            catch (Exception)
            {
                throw;
            }
        }
		
		/// <summary>
        /// Saves a new object to the database
        /// </summary>
        /// <param name="objectToSave"></param>
        /// <returns></returns>
        public T SaveNewObject(T objectToSave)
        {

            ITransaction tx = null;
            try
            {
                tx = Session.BeginTransaction();
                Session.Save(objectToSave);
                tx.Commit();
            }
            catch (Exception)
            {
                if (tx != null)
                    tx.Rollback();
                throw;
            }
            return objectToSave;
        }
		
	 }

Sen får du väll bygga på fecthingstrategies-möjligheter etcetera

Medlem sedan juni 20003 076 inlägg
#3

Tack erka! Det var lite lagomt mycket kod att ta in. :bire
Nu ska jag bara försöka få in lite villkor och sorteringar i detta så blir det riktigt bra! :)

Medlem sedan aug. 20003 575 inlägg
#4

Jag gillar inte namnet DAO jag tycker det skär sig så jag googlade lite och hittade denna sida.
http://in.relation.to/Bloggers/RepositoryPatternVsTransparentPersistence;jsessionid=F2A0568575745D9DF058204AE4026803

Jag gillar Repository, det känns som att man kan säga att NHibernate är det som är DAO i detta fallet och det ni wrappar in det i är en Repository.

Medlem sedan dec. 19996 522 inlägg
#5

Det är ju ett DAO, därav namnet, förstår inte hur du menar att det skär sig? Jag vill inte ha den hårda kopplingen mellan repo och mina domänobjekt, seperation of concerns. Så jag håller med författaren och gillar ett interface / dao approach.

Jag anropar inte dao direkt utan kommunicerar alltid genom ett service interface. Och på det viset får jag en tydligare ingång för olika delar av min applikation, ett service interface kan göra saker i flera iolika daos. På det viset tydligare, men utan en så hård koppling som repo skulle ge

Medlem sedan jan. 20023 327 inlägg
#6

Noterade denna raden:

public interface IGenericDao<T> : [B]IDisposable[/B]

Har själv funderat på att låta mina DAO:s implementera IDisposable. Antar att du har implementationen av "Dispose" i NHibernateDaoBase? Det är i alla fall så som jag tänkt och sedan stänga mitt ISession-objekt etc.

Anledningen till detta är för jag ska skulle vilja kunna använda min DAO i stil med:

using (IUserDao userDao = daoFactory.GetUserDAO())
{
    ...
    userDao.MakePersistent(user);
   ...
}
Medlem sedan dec. 19996 522 inlägg
#7

Det är rätt uppfattat, fast inte i alla implementationer, beror på vilken sessionfilosofi som används

Medlem sedan juni 20003 076 inlägg
#8

erka skrev:

Det är rätt uppfattat, fast inte i alla implementationer, beror på vilken sessionfilosofi som används

Vilka olika filosofier finns?

Medlem sedan dec. 19996 522 inlägg
#9

Vanligast är väll session per request, men även där har du ju lite olika val, du kan ju implementera det som att den flushar sessionen först när requesten tar slut så att säga, eller att det sker efter varje dao. Så att du antingen bara gör det du går in för att göra via dina daos eller att objekt som råkas uppdateras på andra ställen, kanske i din codebehind (eller vad du nu har) automatiskt sparas ner vid flusch.

Medlem sedan jan. 20023 327 inlägg
#10

erka skrev:

Ett service interface kan göra saker i flera iolika daos. På det viset tydligare, men utan en så hård koppling som repo skulle ge

Har du lust att visa ett mindre exempel på hur det kan se ut? Hämtar du dina DAO:s från en IoC-container? Har kollat lite på Castle Windsor men är lite osäker på hur jag ska göra då jag inte riktigt får ihop helheten. Visa gärna i ett flöde (lager för lager). :)

Medlem sedan maj 20012 812 inlägg
#11

Compusa skrev:

Har själv funderat på att låta mina DAO:s implementera IDisposable. Antar att du har implementationen av "Dispose" i NHibernateDaoBase? Det är i alla fall så som jag tänkt och sedan stänga mitt ISession-objekt etc.

Nu använder jag inte NHibernate så jag kan vara ute och cykla, men vad i dina DAO objekt kräver att du implementerar IDisposable. Har det med NHibernate att göra? För annars så ser jag inte någon anledning att implementera IDisposable på "vanliga" DAO objekt. De förstörs ändå själv av GC när de inte används längre

- M

Medlem sedan juni 20008 205 inlägg
#12

Antagligen av samma anledning som alla objekt som använder en resurs är disposable, dvs att det är god ton att fimpa resurser när man är klar med dem, och inte vänta tills nästa gång GC:n behagar gå igång? :)

Medlem sedan juni 20003 076 inlägg
#13

Vad är best practice när det gäller fetchmode?
Jag tänkte att man kan ha en property som innehåller en modeklass men då får jag inte med propertyn eftersom ett interface inte kan innehålla medlemmar.
Så, hur stuvar jag om detta?

public interface IGenericDao<T> : IDisposable
{
        [B]FetchParam FetchParam;[/B] error!!!
}

public class NHibernateGenericDao<T> : NHibernateDaoBase, IGenericDao<T>
{
        /// <summary>
        /// Setting fetchtype on collections
        /// </summary>
        private FetchParam fetchParam;
        public FetchParam FetchParam
        {
            get { return fetchParam; }
            set { fetchParam = value; }
        }

        public T GetObjectById(object value)
        {
            try
            {
                ICriteria criteria = CurrentSession.CreateCriteria(typeof(T));
                criteria.Add(Expression.IdEq(value));

                if (fetchParam != null)
                    criteria.SetFetchMode(fetchParam.Name, fetchParam.Mode);

                return criteria.UniqueResult<T>();
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                CloseSession();
            }
        }
}

public class FetchParam
{
        private string name;
        private FetchMode mode;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public FetchMode Mode
        {
            get { return mode; }
            set { mode = value; }
        }

        public FetchParam()
        {
        }

        public FetchParam(string name, FetchMode mode)
        {
            this.name = name;
            this.mode = mode;
        }
}
Medlem sedan juni 20008 205 inlägg
#14

Interfaces kan inte innehålla fält, däremot kan de ha properties (eftersom properties bara är sockrade metoder, egentligen).

public interface IGenericDao<T> : IDisposable
{
        FetchParam FetchParam { get; set; }
}
Medlem sedan juni 20003 076 inlägg
#15

Ja, men titta där, det funkar ju! Tack spango! :bire

Medlem sedan dec. 19996 522 inlägg
#16

FetchMode kan du lika väll specificera på dina mappningsfiler, det du gör i hql eller criteria overridar det dock. Använder du Lazy Load? FetchMode Eager eller Select är bra att använda just pågrund av problemen med N+1.

http://www.ayende.com/Blog/archive/7627.aspx

Men var vaksam på att du inte får galet långa sql-frågor. SQL-profiler är bra för att fatta hur NHibernate "tänker"

Medlem sedan maj 20012 812 inlägg
#17

spango skrev:

Antagligen av samma anledning som alla objekt som använder en resurs är disposable,

Är det NHibernate som är resursen i det fallet då som måste disposas. Så i DAO's Dispose-metod så gör man en dispose på Nhibernates objekt?

- M

Medlem sedan juni 20003 076 inlägg
#18

erka skrev:

FetchMode kan du lika väll specificera på dina mappningsfiler

Mm, jag har default specat i mappningsfilen och nästan alla collections är specad lazy.
Så om jag vill ladda valda collections till ett objekt så behöver jag overrida via SetFetchMode. Propertyn IList<FetchParam> FetchParams (ändrat från FetchParam) fixar tricket åt mig och jag kan ladda de collections jag vill! :)

Dock har jag nu stött på ett problem som ni kanske kan förklara!

Jag har NHibernateGenericDao<T> i ett eget assambly: BaseDao.
Sen har jag ex. ProductDao i ett annat assambly som ärver ovan.

Om jag sedan kör ex. denna kod i aspx.cb

ProductDao pDao = new ProductDao();
Product p = new Product();
p.Name = "foo";
pDao.Save(p);

så får jag:
The type 'BaseDao.NHibernateGenericDao`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'BaseDao, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

Webprojektet har bara en referens till ProductDao.
Hur undviker jag att behöva lägga till en referens från webprojektet till BaseDao?

Medlem sedan aug. 20003 575 inlägg
#19

Det beror på var du har interface't

Medlem sedan jan. 20023 327 inlägg
#20

Gladh skrev:

spango skrev:

Antagligen av samma anledning som alla objekt som använder en resurs är disposable,

Är det NHibernate som är resursen i det fallet då som måste disposas. Så i DAO's Dispose-metod så gör man en dispose på Nhibernates objekt?

- M

NHibernate-session (databasanslutningen) är resursen. När man är klar med användingen av DAO:n, så stänger/lämnar man tillbaka anslutningen till connection-pool:en. Det var i alla fall min tanke, men det hela.

262 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
124 ms — deklarationer (db)
0 ms — hämta statistik (cache)
135 ms — hämta tråd, inlägg och bilagor (db)
121 ms — ändringar (db)