Entity Framework 4 POCO, Repository and Specification Pattern [Upgraded to CTP5]

Before reading this, you might want to read these two posts first:

You might have been aware that MS just released Entity Framework 4 CTP5 some days ago. There have been some comments asking me when the data access layer would be upgraded to that version. Since I had been quite busy these days,  the answers for these questions was just a promise that I would do the upgrade when I had time after I finished investigating the new release carefully. However, some readers seem to be anxious waiting for the code updated so they keep asking me for the progress (and I feel good because I know there are some ones who are interested in the framework I built :)).

So, today I decided to fulfill my promise: the source code has been updated in google code. You can download the latest version (1.3 at this  writing) here http://code.google.com/p/ef4prs/downloads/list

Note: to be able to compile the code, you must first download and install EF4 CTP5.

Some implementation notes:

- The assembly is now changed to EntityFramework.dll and located at C:\Program Files (x86)\Microsoft ADO.NET Entity Framework Feature CTP5\Binaries\EntityFramework.dll

- Base mapping class has changed from EntityConfiguration<T> to EntityTypeConfiguration<T>

- Entity Framework team seems to concentrate on implementing DbContext much more than ObjectContext. But if you want to access to ObjectContext from DbContext, here is the way:

ObjectContext ctx = ((IObjectContextAdapter)_dbContext).ObjectContext;

- We do not need to register entity any more, just add mapping class(es) to the ModelBuilder then we are all set. Well, this is for your information only, since this framework will do this automatically in the XContextBuilder class.

- The most and important thing, I think, is EF now will automatically map entity relationships without explicitly writing the mapping code. For example:

I have an entity Customer that has many Orders. These two classes will be defined as below:

public class Customer : Entity
{
    public Customer()
    {
        Orders = new List<Order>();
    }

    public virtual string Firstname
    {
        get; set;
    }

    public virtual string Lastname
    {
        get; set;
    }

    public virtual IList<Order> Orders
    {
        get;
        set;
    }

    public virtual DateTime Inserted
    {
        get; set;
    }
}

public class Order : Entity
{
    public Order()
    {
        OrderLines = new List<OrderLine>();
    }

    public virtual IList<OrderLine> OrderLines
    {
        get;
        set;
    }

    public virtual DateTime OrderDate
    {
        get; set;
    }

    public virtual Customer Customer
    {
        get; set;
    }
}

Here is the mapping classes:

public class CustomerMapping : EntityTypeConfiguration<Customer>
{
    public CustomerMapping()
    {
        HasKey(x => x.Id);

        Property(x => x.Firstname).IsRequired().HasMaxLength(25);
        Property(x => x.Lastname).IsRequired().HasMaxLength(25);
        Property(x => x.Inserted);

        //we dont need to write this code to specify the relationship, this will autolatically done by EF
        //HasMany(x => x.Orders).WithRequired(y => y.Customer).HasForeignKey(c => c.CustomerId);

        ToTable("Customer");
    }
}

public class OrderMapping : EntityTypeConfiguration<Order>
{
    public OrderMapping()
    {
        HasKey(x => x.Id);

        Property(x => x.OrderDate);

        // No need to write mapping code to Customer
        //HasRequired(c => c.Customer);

        ToTable("Order");
    }
}

With these mappings, EF will generate the Order table with a foreign key to Customer table as below:

You can download and check out the test code to see other mapping scenarios like many-to-many or how to change the table name in the mapping code.

Happy coding!

About these ads

Posted on December 16, 2010, in Entity Framework and tagged , , , . Bookmark the permalink. 115 Comments.

  1. Super. Will check it out.

  2. The one thing I don’t get is passing the mappingAssemblies manually. There’s got be a better way to scan (reflection or IoC) and find assemblies containing EntityTypeConfiguration and just load them in automatically. Thoughts?

    • IMO, the reason for not using an IoC is that I dont want the framework to tight to it. In other word, I dont want the framework to have a dependency on an IoC container.

      Reflection is slow, yes, but I think it is accept table because the scan often happens at application start up. If speed is matter, then caching assemblies can be a solution to consider.

  3. I got you. A follow-up to that is On BeginRequest, you actually pass in the assembly name via the .Init method. Besides an IoC, shouldn’t that be done on start-up and not on every request? I see you initialize the context once but it’s unintuitive to me to pass a mapping assembly in BeginRequest instead of start-up. Can you elaborate?

    • Initializing the ObjectContext in BeginRequest and close it on EndRequest is an approach to manage ObjectContext life-cycle which is specific to Web application. You can refer to “Open Session In View” approach (from Java community): http://community.jboss.org/wiki/OpenSessioninView to get understanding on why we do not initialize ObjectContext on start up but every request.

  4. Thanks for the info.

  5. Looks like there’s a bug in CTP5. When inherit from a base entity with Id and try to do many to many mapping, you will get a “Sequence contains more than one matching element”

    Not sure what’s you take on it. I actually felt very awkward having all classes with the same field called Id.

    • Yes, that’s the problem with CTP5 that I faced, too. I had an discussion (comment) on this at: http://areaofinterest.wordpress.com/2010/12/08/dynamically-load-entity-configurations-in-ef-codefirst-ctp5/. The author said that it seems the problem comes from the mapping itself and I am not sure how to get rid of that problem at the moment.

      • Is it a common practice to have all the classes inherit from base and have the same Id field?

        Given a choice, I would use Product.ProductId, Category.CategoryId, and they often have different type and assigned value rather than db generated identity field, like EmployeeId.

        Are there any potential problems using your framework if I move all the Id fields out of the base entity?

      • I think you cannot do that without changing the code. For instance, the GetByKey(id) method on the Repository uses the hard-coded entity key as “Id”. So I think when you are not using Id for the key, you have to change the implementation.

      • I just do the mapping at the concrete class level. For example, with a base User and Employee/Patient, use Haskey at Employee and Patient class. It works for simple update, haven’t try on complicated graph with multiple change/insert/delete, etc.

        BTW, find out lots of good stuff you put in there. For example, didn’t realize the Update in GenericRepository actually does several things I was struggling to do manually. It’s really great. Thanks.

  6. Hi,
    How can I use ef4prs for CTP 5.0 on WCF Services? I want to handle change tracking on server-side. Is this possible on CTP 5.0 using native class (like poco)

  7. Using this framework, how would you be able to utilize the Seed method. I need to seed static values into a table. Usually that’s done overriding the DbContext Seed method or the Initializer’s Seed method. Any idea?

    • I think in this case, you may have to

      1) Manually create a DbContext instance yourself, e.g. MyDbcontext which inherits from DbContext

      2) Declare all the DbSet[EntityType] as public properties on the MyDbContext

      3) Override the OnModelCreating method to add the mapping classes

      4) Create a class, e.g. DataSeedingInitializer which inherits from DropCreateDatabaseAlways[MyDbContext]. In this class, override the Seed method to seed the data

      5) In the application start up code, call:

      DbDatabase.SetInitializer(new DataSeedingInitializer());
      MyDbContext context = new MyDbContext(“DefaultDb”);
      // some of your extra code to store the MyDbContext

      6) Every when you want to create an instance of GenericRepository, do something like this:

      MyDbContext context =
      IRepository repository = new GenericRepository(context);

      7) Use the repository.

      FYI. I added some test classes under Lab folder of the Infrastructure.Tests assembly to demonstrate almost all of above steps, except the code to store and manage the MyDbContext. Please check out the code at http://code.google.com/p/ef4prs/source/checkout and try it.

      You can extend or make any changes you want to meet your need.

      Hope this help.

      • Thanks huyrua. IMHO, I think you should support it via ObjectContextBuilder. You have ObjectContext there, so you can allow another method that would be called to seed something based on specific TEntity. You can then call ObjectContext.SaveChanges() after seeding is done. I don’t know enought about he ObjectContext but I see it has methods to retrieve an entity and save and that’s all we need. Thoughts?

    • Frank,

      Why wouldn’t we create a class that wraps the DbContext to seed the data at application startup, just right after the DbContext being initialized? Below code demonstrates how to initialize DbContext and also seeds the initial data in ASP.NET MVC application


      public class MvcApplication : System.Web.HttpApplication
      {
      // other code ...
      public override void Init()
      {
      base.Init();
      _storage = new WebDbContextStorage(this);
      }

      protected void Application_BeginRequest(object sender, EventArgs e)
      {
      DbContextInitializer.Instance().InitializeDbContextOnce(() =>
      {
      DbContextManager.InitStorage(_storage);
      DbContextManager.Init(new[] { Server.MapPath("~/bin/mapping-assembly.dll") });

      new DataSeeder(DbContextManager.Current).Seed();

      });
      }
      private WebDbContextStorage _storage;
      }

      I also think that in the Seed method you might have to check for the existence of the seed data because that method will be run again and again when the application is restarted.

      It’s just an idea, you may already have a better solution though.

  8. Huy,

    Happy holidays! Question for you: when attempting to use the set of Get methods with paging support (i.e. which use ‘skip’ and ‘take’ parameters), the LINQ-to-EF dies with this exception (to paraphrase): “can only use skip and take on a sorted collection; please use orderby before skip and take”.

    Since this a fully generic repository, it’s not possible to specify a “strongly-typed” OrderBy (e.g. “x => x.Name”), so my solution thus far was to use the System.Linq.Dynamic library and change the fundamental GetQuery to be:

    public IQueryable GetQuery(string sortParameter = “Id”) where T : class
    {
    return DbContext.Set()
    .OrderBy(“it.” + sortParameter); // Uses System.Linq.Dynamic; defaults to “Id”
    }

    Thus, if the “sortParameter” is not specified, it will fall back to a default sort of “it.Id” (by ID); but otherwise, you can specify any other property of the current object to sort by. Adding the sort here satisfies the L2E skip and take requirements further “downstream” – the exception is gone, and I am able to use “true” paging where required.

    Opinions on this approach? Is there a better way?

    Allen

    P.S. Following along, I am also able to add overloads of the paged Get methods which return the total count of records as an out parameter, by using your built-in Count methods:

    public IEnumerable Get(ISpecification criteria,
    int pageIndex,
    int pageSize,
    out int count,
    string sortParameter = “Id”) where T : class
    {
    count = Count(criteria);

    }

    • Allen,

      That’s obviously a bug of the Get methods with paging parameters (pageIndex, pageSize). Thanks for pointing it out. I sometimes faced that error but just did not know why I did not fix it.

      Actually, when I want to get entities in pages, I usually do something like this:

      Repository.GetQuery[Entity]().Where(expression).OrderBy(expression).Skip(pageIndex).Take(pageSize).AsEnumerable();

      So, regarding the bug of the Get methods with paging parameters, I will remove them out of the Repository to eliminate the errors that may happen. The reason is I don’t really like the magic string for sortParameter which is error prone IMHO. I hope you feel comfortable with this. Otherwise, you can absolutely change or add more overload methods to perform ordering like the idea you proposed :)

      Thanks.

      • Can’t you do something like this to add a strongly typed sort?

        public IEnumerable Get(int pageIndex, int pageSize, Func orderBy) where TEntity : class
        {
        return GetQuery().OrderBy(orderBy).Skip(pageIndex).Take(pageSize).AsEnumerable();
        }

      • Sorry, the Func got blocked out in the post, it should be

        Func orderBy

      • The angle brackets keep getting cleansed, Func should have a TEntity, string in angle brackets

  9. So I pulled the source and added this to IRepository and both GenericRepository classes:


    public IEnumerable[TEntity] Get[TEntity](int pageIndex, int pageSize, Func[TEntity, string] orderBy) where TEntity : class
    {
    return GetQuery[TEntity]().OrderBy(orderBy).Skip(pageIndex).Take(pageSize).AsEnumerable();
    }

    and added this test to your Test() method in RepositoryTest.cs:

    private void GetProductsOrdered()
    {
    var output = repository.Get[Product](0, 5, x => x.Name).ToList();
    Assert.IsTrue(output[0].Name == "Windows Seven Home");
    Assert.IsTrue(output[1].Name == "Windows Seven Premium");
    Assert.IsTrue(output[2].Name == "Windows Seven Professional");
    Assert.IsTrue(output[3].Name == "Windows Seven Ultimate");
    Assert.IsTrue(output[4].Name == "Windows XP Professional");
    }

    and sure enough, all tests passed.

    PS, make sure to convert square brackets to angle brackets where appropriate in the above code.

    • That’s great. I’ll update the source code following your proposed solution.

      Thanks.

    • I like it! I could not wait huyrua update, should I?

    • The source code has been updated with paging support following cconway25′s solution. Check it out at http://code.google.com/p/ef4prs/source/checkout

    • Yesss! This is the solution I was looking for.

      In conjunction with keeping some overloads to fall back on the “default sort”, now we can have the option to keep the API surface as clean as it was in Huy’s original implementation, and yet now have the ability to pass in a strongly-typed orderby as necessary anytime.

      Huy, also, if you make the “queryOrder” parameter (enumeration) optional, defaulting to QueryOrder.Ascending (or descending), the method signature will become one parameter cleaner and still retain all this new functionality.

    • Quick question on the most recent update: if the parameter to order by is something other than string, what are the possible options? For example, given that the parameter “Id” below is an int:

      var output = repository.Get[User](x => x.Id, 0, 5).ToList();

      This will fail with an “unable to convert int to string”. On the other hand, if you do this:

      var output = repository.Get[User](x => x.Id.ToString(), 0, 5).ToList();

      You will get the lovely “unable to convert ToString() into a store expression” (one of those characteristic things about EF). There has to be something better than:

      var output = repository.Get[User](x => SqlFunctions.StringConvert((double)x.Id), 0, 5).ToList();

      This surely does work – but… ughhh. Ideas?

      • Actually, the expression x => x.Id means: I want to sort on the column which is named Id, not the value of Id, so we dont need to cast it to string or double in this case.

        For more information, see the below comment from cconway25 (I hop you did).

        Thanks.

  10. Allen/huyrua,

    You could change the signature to:

    IEnumerable[TEntity] Get[TEntity, TOrderBy](Expression[Func[TEntity, TOrderBy]] orderBy, QueryOrder queryOrder, int pageIndex, int pageSize) where TEntity : class;

    and call it like this:

    var output = repository.Get[User, int](x => x.Id, QueryOrder.Ascending, 0, 5).ToList();

    or

    var output = repository.Get[Product, double](x => x.Price, QueryOrder.Ascending, 0, 5).ToList();

    or create it as an overload since most sorting (I think) is done on string properties and this would leave the API clean for most use cases but flexible enough for other sort scenarios.

  11. How do I reach context.Database.SqlQuery or context.ExecuteStoreQuery?

    Thanks

    • It’s not supported just yet, but you can extend the Repository to add methods to execute the stored query.

      • Thanks. I just learned that you can not control lazy loading on scalar fields. So if I load message object, message body always get loaded? I tried returning IQueryable, which allows you to control which fields to load. But it doesn’t work if the class contains other complex objects, because those objects are not loaded with IQuerayble, and throw an error when you try to reference to fields inside the other objects.

        This is really really bad. I have been trying hard to convince our management and DBAs that EF is more efficient and productive. But now I start doubting myself.

      • Since we enable lazy loading by default, then the message body won’t be get loaded.

        I think LINQ to Entities supports getting scalar field (not verified it yet with a profiler whether it will load the whole entity then performs selecting only a property in-memory). Like below:

        var personName = from p in Repositoty.GetAll[Person]) select { p.Name }

        If you have time, you could verify whether or not EF will issue an SQL to select only Name field in the Person table. If it doesn’t, feel free to add an overload method in the IRepository to support executing Stored query.

        Hope this help.

      • If repository returns IQueryable, you can control which field get loaded and it does generates the right select in SQL. The problem is any computed field, as simple as get {return “test”;}, will not work.

        You got “The specified type member ‘ComputedFieldName’ is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.”

        If you happen to know the solution and be a dedicated workaholic, let me know. Otherwise, happy new year ^_^

  12. Hello

    I’m wondering if this framework can be used on WPF application, Specifically if the ObjectContext will better created once per application (and where is the best place to initialize it) using the ObjectContextManager or once every time the Business Object need it using the ObjectContextBuilder.

    Also is there a way to run Unit Test against the framework without persisting to the data base?

    Thank you

    • 1)

      The test class – RepositoryTest – show how to initialize the ObjectContext via ObjectContextManager with a SimpleSessionStorage that you can refer to when using the framework in WPF.

      2)

      You can use the rollback pattern:

      In the test feature setup, start the transaction:

      Repository.UnitOfWork.BeginTransaction();

      In the test feature tear down, rollback transaction:

      Repository.UnitOfWork.RollbackTransaction();

      Hope this help.

  13. Hi Hayrua,
    Could you please remark deffered loading another meaning LazyLoadingEnabled=false).

    All samples from web or msdn advice us.
    DbQuery<Category> categories = context.Categories.Include(“Products”);

    But I would like to load childs -or others- without path “string”, it could produce run-time exceptions and many bugs… I would like to use type instead of “Products”.

  14. HUYRUA,
    Is is possible to increase performance by instanciating one repository per HttpContext?
    Rick Strahl has a good sample on LINQ to SQL at: http://www.west-wind.com/weblog/posts/246222.aspx
    A EF version is also explained at: http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx
    Please let me know what you think.
    thanks.

    • You can use the WebObjectContextStorage already implemented in the framework. The summary of that class explains how to use it. in Web context.

      Hope this helps.

  15. Quick question, how would I go about changing the database column name of the Id in my mapping class in CTP5? I used to be able to do it with MapSingleType but that doesn’t exist anymore. ‘Property’ has a HasColumnName that allows me to specify what the database column name is, but I don’t see a mechanism for it for the identity (‘HasKey’).

  16. Good question, cconway25.

    I just tried and found a way that beside the HasKey method, you must add Property method to specify the column name, as below example for Customer entity:


    HasKey(x = > x.Id);

    Property(x => x.Id).HasColumnName("CustomerId");

    Hope this helps.

  17. HUYRUA,

    Thank you for sharing the great library. I have a question around the Unit of Work (UoW) pattern that you put together.

    UoW is tied to a Repository and I am wondering how can it work across repositories. Can the UoW implementation be a singleton to address this issue. And also for the two-phase commit across the databases (with different dbContexts) can the UoW use TransactionScope instead of the Transaction as I believe TransactionScope works like a regular Transaction (with out DTC) for dbcontexts with the same connection string.

    Thanks

    • If I am working with multiple databases via different DbContext, the TransactionScope should be used to commit the transactions. That said, each call to XRepository.UnitOfWork.SaveChanges() will not make any change to a database until the TransactionScope is committed.

  18. Hi,
    Thanks alot for giving a quick start to all of us.
    I am trying to checkout the latest code base as mentioned in http://code.google.com/p/ef4prs/source/checkout
    , but getting error while doing checkout using Tortoise SVN:

    http:\ef4prs.googlecode.com\svn\trunk’ is not a working copy
    Any help…
    Thanks,

  19. I’m trying to do an entity splitting.

    public class FooItem
    {
    public int Id { get; set; }
    public string ItemId { get; set; }
    public string ItemName { get; set; }
    public string ItemDisplayName { get; set; }
    }

    split into MainTable {Id, ItemId, ItemName} and OptionalTable {ItemId, ItemDisplayName}


    public class FooItemMapping : EntityTypeConfiguration {
    public class FooItemMapping {
    .Map(m =>
    {
    m.Properties(p => new
    {
    A_Id = p.Id,
    A_ItemId = p.ItemId,
    A_ItemName = p.ItemName
    });
    m.ToTable("MainTable");
    HasKey(x=> x.Id);
    })
    .Map(m =>
    {
    m.Properties(p => new
    {
    B_ItemId = p.ItemId,
    B_ItemDisplayName = p.ItemDisplayName
    });
    m.ToTable("OptionalTable");
    HasKey(x=> x.ItemId);
    });
    }

    I couldn’t make the above mapping code work, even without the optional table. it’s OK when I do

    Property(x=>x.Id).HasColumn("A_Id");
    ...

    I was hoping it generates the SELECT FROM Main LEFT JOIN Optional ON ItemId.

    Anyone has an idea what I’m missing? Thanks.

  20. DbContext not doing eager loading?

    Since I can’t do entity splitting, I tried the following

    public class FooItem
    {
    public int Id { get; set; }
    public string ItemId { get; set; }
    public string ItemName { get; set; }
    public FooItemDisplayName ItemDisplayName {get;set;}
    }

    public class FooItemDisplayName {
    public string ItemId {get;set;}
    public string ItemDisplayName {get;set;}
    }

    With all the mapping set, I try to load in the repository

    GetQuery(x=>x.Id == 123).Include(y=>y.FooItemDisplayName).ToList()

    With ObjectContext, everything works fine. But when trying DbContext in the Lab, it does not do eager loading. Not sure if this is an EF DbContext issue, or the this repository framework.

    I understand the DbContext in Lab is experimental, so just mentioned here FYI.

    Thanks.

  21. Forgive me for another naive question.

    When do you call UnitOfWork.BeginTransaction() explicitly vs just UnitOfWork.SaveChanges()? I ask this because I’m trying to integrate some code from another NHibernate based framework. It has a global TransactionManger that has

    public TResult ExecuteCommand(Func command)

    It executes all requests by calling begin and commit transaction, and also add business warnings and catch business exceptions, then add it to the dto response. It’s a neat way to handle exception and warnings at service layer.

    I’m not sure if I fully understand either framework and wonder if this global TransactionManager compliment your objectcontext management code, or you already have this just that I didn’t get it.

    Thanks.

    • Code lost, another try

              public TResult ExecuteCommand(Func command) 
                  where TResult : class, Common.Message.IDtoResponseEnvelop
              {
                  try
                  {
                      BeginTransaction();
                      var result = command.Invoke(Locator);
                      CommitTransaction();
                      CheckForWarnings(result);
                      return result;
                  }
                  catch (BusinessException exception)
                  {
                      if (IsInTranx) Rollback();
                      var type = typeof(TResult);
                      var instance = Activator.CreateInstance(type, true) as IDtoResponseEnvelop;
                      if (instance != null) instance.Response.AddBusinessException(exception);
                      return instance as TResult;
                  }
                  catch (Exception e)
                  {
                      throw;
                  }
              }
      
    • UnitOfWork.SaveChange() implicitly commits the transaction with IsolationLevel is ReadCommitted. This is the default implementation of underlying ObjectContext and/or DbContext.

      When you want to start a transaction with the IsolationLevel other than ReadCommitted, you should call UnitOfWork.BeginTransaction([IsolationLevel]) then UnitOfwork.CommitTransaction() or UnitOfWork.RollBackTransation().

  22. How can I deal with stored procedure in this code?
    Is there FunctionImport method to import SP?
    Thanks,
    Oleg

    • It does not support calling stored procedure yet, but here is a possible way that uses Materializer (included in EFExtensions that can be downloaded at http://code.msdn.microsoft.com/EFExtensions/Release/ProjectReleases.aspx?ReleaseId=3624):

      1) Create an entity that store a result of stored procedure, e.g.


      public class ResultEntity
      {
      public string Field1;
      public int Field2;
      }

      2) Sub class GenericRepository and add method(s) to execute store procedure. For example:


      public class XYZRepository : GenericRepository
      {
      public ResultEntity GetSomeThing(string spName)
      {
      Materializer materializer = new Materializer
      {
      Field1 = r.Field("Field1");
      Field2 = r.Field("Field2");
      DbCommand command = this.ObjectContext.CreateStoreCommand(spName, CommandType.StoredProcedure, null);
      ResultEntity result = materializer.Materialize(command).SingleOrDefault();
      return result;
      }
      }
      }

      The code is not tested yet, but I hope you get the idea.

  23. How can I detach an entity to work with it in another context? I have already added the detach method to IRpository but I’m still stuck since it doesn’t seem to be detached. Should I detach child objects as well? (E.G. I have album entity which has a navigationproperty to AlbumImages. Should I detach album Images one-by-one too?)
    Is there any generic way to do this?
    Thanks.

  24. One more thing I’d like to note:
    If we want to use this framework in a web application, with WebContextManager, we should add:
    private WebObjectContextStorage _storage;
    ObjectContextInitializer.Instance().InitializeObjectContextOnce(() =>
    {
    ObjectContextManager.InitStorage(_storage);
    ObjectContextManager.Init(new[] { Server.MapPath(“~/bin/mapping-assembly.dll”) });
    });
    }
    Which means adding a reference to DAL (Infrastructure.Data.EntityFramework) to the UI which is something I’d like to avoid.
    is there any other way to initialize ObjectContext? (e.g. in BLL maybe?)

    • A possible solution I thinh you can consider is implementing a BootStrapper class which does all the initialization for ObjectContext/DbContext (and something such as IoC container). This class will then be called in the Global application.

  25. I want to go with the data annotation, what will be the best way to do that in this framework? thank you

    • The data annotation is the new feature since the CTP5 release and it is not incorporated to this framework yet, I also dont have plan to apply this but some initial thoughts of mine is that you might not need to use the mapping classes if you are applying data annotation for entities. There might be more or less works to do with this but… please bear with me that at the moment I dont have time to think deeply about this until the final release of EF.

  26. Hi Huyrua

    When I try to create a unit testing project using NUnit and trying to test the EF based application that uses your framework, I getting the following error:

    The mapping of CLR type to EDM type is ambiguous because multiple CLR types match the EDM type ‘POCOYYY’. Previously found CLR type ‘XXX.Data.Domain.POCOYYY’, newly found CLR type ‘XXX.Data.Domain.POCOYYY’.

    Any help on this greatly appreciated!!

    thanks
    Kris

  27. Hey Huyrua,

    I am wondering why does the Update method on line 179 inside

    ef4prs\Infrastructure.Data.EntityFramework\Lab\GenericRepository.cs

    It’s empty :(


    public void Update(TEntity entity) where TEntity : class
    {
    }

    • With the lab version which uses DbContext, you dont need to call Update() method which left empty, but SaveChange() or Repository.CommitTransation() if there is an opening Transaction.

  28. Hi Huyrua

    I stuck with many-to–many relation.
    My database has no foregin key, instead of them triggers used for referential integrity.
    Do I need to define something like HasMany in mapping classes in this case?

    I have three tables (and three entity classes):
    1. SqlFieldDataType
    2. SqlOperator
    3. SqlFieldDataTypeSqlOperator

    I am getting next error:

    One or more validation errors were detected during model generation:

    System.Data.Edm.EdmEntityType: : EntityType ‘SqlFieldDataTypeSqlOperatorMapping’ has no key defined. Define the key for this EntityType.

    Any ideas?
    Thank you
    Oleg

    • If SqlFieldDataTypeSqlOperator contains only the keys of the other table (a many to many relationship) then you don’t need to create a mapping class SqlFieldDataTypeSqlOperatorMapping. Please take a look at the demo mappings for Product and Category in the source code.

      Thanks.

  29. I have two suggestions for improving/removing bugs.
    In GenericRepository.cs, instead of hard coding ObjectContext in GetEntityName, we can do:
    private string GetEntityName() where TEntity : class
    {
    return string.Format(“{0}.{1}”, ObjectContext.DefaultContainerName,_pluralizer.Pluralize(typeof(TEntity).Name));
    }

    Also, GetByKey method only works for entities with primary fields named Id. We can add a method to extract the key property name and then, create the new entity key:
    private EntityKey GetEntityKey(object keyValue) where TEntity : class
    {
    var entitySetName = GetEntityName();
    var objectSet = ObjectContext.CreateObjectSet();
    var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
    var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
    return entityKey;
    }
    Then we can call this method from GetByKey method like:
    EntityKey key = new EntityKey(fqen, ENTITY_KEY_NAME, keyValue);
    I have tested this a it worked ok. But I’m not sure if I am missing something. What do you think huyrua?

  30. It has been a while, hope you are still tracking this.

    I’m thinking about using NBuilder to create some in-memory data for unit testing. I have some business logic in the entities and some query logic in the customRepository. Service layer calls customRepositories, but for simple ones, they also go directly against generic repository.

    Where does NBuilder fit into this picture? Especially for testing the query logic.

    Thanks.

    • I have no knowledge of NBuilder so I do not have strong opinion on this. If you have any of great suggestion, please share.

      • NBuilder basically takes any entity class and builds test data using fluent syntax, very convenient for creating all kinds of unit test scenarios. I guess the real question I was trying to ask is how to test the repository. Most online articles suggest creating a fake repository or mock, but none of those test the real thing.

        In my case, there are lots of query logic using custom or generic repository (getting user list but exclude some based where they sit) and many calculated properties in the entity (displayname based on real name, nickname and bunch of other things, etc).

        I can test entity level rules by creating a list using NBuilder. But how can I test the repository queries without creating a FakeCustomerRepository, and without relying on a live database through EF? Speed is one thing, our data also come from bunch of other systems on demand, making it impossible to auto test live.

        I’m trying to figure out where do I plug-in the in-memory test data for repository test. Is there an easy way to swap out EF GenericRepository implementation and fill the data there (Infrastructure.Data.InMemory)? Or do I have to make all the queries using specification pattern so I can test queries independent of repository?

        Thanks.

      • Here is my 2 cents opinion/experience about unit testings:

        - If I am testing business/service layer, the repository should be mocked. In this case, a ‘FakeRepository’ should be employed that returns hard-coded data as a result of query operations,… This is so-called ‘test isolation’. Note that I don’t have to explicitly implement a FakeRepository class, instead, I use a mocking framework like Rhino Mock to create an instance of IRepository.

        - If I am testing the data access layer, e.g. repository classes, then IMHO, I have to open the real database connection as well as apply ‘roll back’ pattern to keep the data unchanged when each test is executed. And yes, it slows the test because of database operations, but I think it is a must to make sure the repository should work as expected against a production database.

        Thanks.

      • Thanks for the update. Those are the solutions I have been reading about. But sometime it’s hard to separate business logic from the repository. For example, I get a list of test result back, but need to filter down based on certain keywords, user group, department and location without bring them all in first, so the query stay with repository. The repository, query and EF stuff can be tested against live database as integration test. However, automated unit tests are almost impossible, some test cases aren’t even exist in live database.

        I tried to move most queries into specification, then use NBuilder to build collection AsQueryable and feed it to SatisfyingEntityFrom … similar to what you have in Find(Specification), which the service layer calls. This allows query to be tested separately and also works correctly against real database.

        But I’m not really sure if I’m heading for the right direction. Also trying to figure out how to make more complicated specifications beyond x.Name==”whoever”, like join,group,max, etc. using expression. Looks like it should be possible.

      • Just realized that all queries are written in LINQ, so in theory it shouldn’t matter what the data sources are. Somewhere in the framework, you should be able to intercept and plug in a collection generated data that feed into the repository and test the query logic, right? Any hint where? Thanks.

  31. How do you integrate dependency injection into your sample using structureMap? Thanks

  32. I have a requirement to use Self Tracking Entites by sending only the changed values to the database.

    I have found the following great article explaining how it can be done.

    http://blogs.msdn.com/b/adonet/archive/2011/02/09/self-tracking-entities-original-values-and-update-customization.aspx

    I am wondering, is there a way to incorporate the changes mentioned in this article into your library and make it to work with CTP 5 / DbContext / POCO scenarios.

    Thanks

  33. Are there anything fundamentally wrong implementing read-only queries as extension method? Like

    static NewlySubscribed(this IQueryable query, int days) { }
    ... ...

    GetQuery().NewlySubscribed(days).InZipCode(zipcode).WhateverElse();

    I have also tried the same with specification, like

    Find(NewlySubscribedSpec().And(InZipCodeSpec)...

    But often queries do not feel natural as specification (I have read queries are NOT spec and should be treated differently). Besides, it’s also much easier to throw in some stored procedure calls when using extensions. Testing query logic (not the EF part) is also very intuitive.

    Is this a viable options, or do I miss something important? Thanks.

    • There is nothing wrong with extension method you explained, IMO. They are methods for querying specific piece of data out of this generic framework.

      The point here is, I think, it shouldn’t be put in the infrastructure but somewhere else, e.g. business layer or a satellite .NET assembly which is specific for a particular business domain. The same thoughts for specifications.

      Thanks.

      • Thanks for the update. Yes, all the query logic and extensions are in business layer, next to repository and called from service layer. After a few tries, I like specification better than extension after all.

        Some of our queries are like FindTopCustomerInEachCategory, which is more likely done in a stored procedure for performance reason. I was wondering if it’s possible to embed a stored procedure inside a specification, so you can find new star customers with something like

        Find(TopCustomerInEachCategorySpec(10).And(NewlySubscribedSpec(30))

        Is that possible? Or make sense at all?

      • From a specification, it’s impossible to execute a stored procedure from IQueryable instance because it only ‘sees’ an IQueryable. Although you can do that from the ObjectContext with the methods like CreateStoreCommand or ExecuteStoreQuery, etc. but you might need to extend the repository (or subclass it) to expose these methods to the caller.

        Hope this helps.

  34. Hi huyrua,
    I stumbled upon your blog and I find it very useful in my experimentation. I hope you don’t mind me borrowing your work. Anyhow, I can’t get off of this mapping error that says

    SetUp : System.InvalidOperationException : The configured property ‘CompanyAddress’ is not a declared property on the entity ‘Company’. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

    My mapping class is:
    public class CompanyMapping : EntityTypeConfiguration {
    public CompanyMapping()
    {
    HasKey(o => o.Id);
    Property(o => o.ConcurrencyToken)
    .IsConcurrencyToken()
    .IsRequired()
    .HasColumnType(“rowversion”);

    Property(o => o.Id).HasColumnName(“CompanyId”);
    ToTable(“Company”);
    }
    }

    ICompany interface

    public interface ICompany {
    int? CompanyAddressId { get; set; }
    int? ShipToAddressId { get; set; }
    int? BillToAddressId { get; set; }
    int GenerationNumber { get; set; }
    string Name { get; set; }
    string LegalName { get; set; }
    string BusinessPhone { get; set; }
    string BusinessFax { get; set; }
    string Email { get; set; }
    string Url { get; set; }
    string GovernmentTaxID { get; set; }
    bool IsActive { get; set; }
    IAddress CompanyAddress { get; set; }
    IAddress ShipToAddress { get; set; }
    IAddress BillToAddress { get; set; }
    }

    Company entity

    public class Company : Entity, ICompany {

    public virtual int? CompanyAddressId
    {
    get;
    set;
    }

    public virtual int? ShipToAddressId
    {
    get;
    set;
    }

    public virtual int? BillToAddressId
    {
    get;
    set;
    }

    public virtual int GenerationNumber
    {
    get;
    set;
    }

    public virtual string Name
    {
    get;
    set;
    }

    public virtual string LegalName
    {
    get;
    set;
    }

    public virtual string BusinessPhone
    {
    get;
    set;
    }

    public virtual string BusinessFax
    {
    get;
    set;
    }

    public virtual string Email
    {
    get;
    set;
    }

    public virtual string Url
    {
    get;
    set;
    }

    public virtual string GovernmentTaxID
    {
    get;
    set;
    }

    public virtual bool IsActive
    {
    get;
    set;
    }

    [System.ComponentModel.DataAnnotations.ForeignKey("CompanyAddressId")]
    public IAddress CompanyAddress
    {
    get;
    set;
    }

    [System.ComponentModel.DataAnnotations.ForeignKey("ShipToAddressId")]
    public IAddress ShipToAddress
    {
    get;
    set;
    }
    [System.ComponentModel.DataAnnotations.ForeignKey("BillToAddressId")]
    public IAddress BillToAddress
    {
    get;
    set;
    }
    }

    The error only occurred after I change Address CompanyAddress to IAddress CompanyAddress.

    Also, you can see in my code how I create my foreign key relationship which I think little bit ugly. The reason is that, I’d like to control how the field name will reflect in my database. I hope there is a neater way to do this probably in mapping class.

    Thanks for the help and appreciate your effort!

    • Correction on Mapping class.. EntityTypeConfiguration
      The did not show up in the post.

      • I think the exception is obvious that you cannot use the interface but a primitive type OR a concrete entity, e.g. CompanyAddress. I am not sure if there is a way to map the relationship between an entity with an interface (like Company and IAddress in you case) but currently the framework does not seem to support that way of mapping.

  35. Yeah, just found it out just now. I get away of the error and by removing data annotations but as you said it seems like ef ctp5 does not support mapping entities with interface. Too bad! This would seemingly affect my whole design.

  36. Hi Huyrua,

    u making upgrade to EF4.1. Haven’t actually red are there any major changes compared to ctp5 and one could probably do the upgrade himself but it would be nice to have your official version with maybe some improvements mentioned by other users here.

    anyway really good job dude, i actually made some nice money on a project using your repository pattern implementation.

    Thx i guess:)

    • Andy,

      It’s good to know you find the framework helpful and also made some money frome it :)

      I know that there is no official realease which incorporate changes from people’s comment up till now. But since there will be an official release of EF by this month as announed from Microsoft, lease wait until that time.

      Thanks.

      • Well the Release Candidate of EF4.1 is allready out (just in case u haven’t maybe noticed) for 2 days now and they said there will be no changes from on framework level (just evaluating and fixing eventual bugs reported by users) before the final release which is due in less than a month.
        But as you said maybe it’s better to wait till the real stuff comes out, just to be sure.

        Anyway i’m looking forward of what will you come up with :)

      • Oops.. You’re right I haven’t noticed the 4.1 release because of being on vacation these days. Will check it out. Thanks

  37. First of all, I love your work here. I have been looking for a solid EF 4 repository pattern for almost 2 weeks now and yours blows everything else away. So thanks for sharing and great job.

    I have adapted your pattern slightly (really just going backwards) to take out the specification (at least for now i’m happy with just linq) and the objectcontextbuilder/manager. Also I am using EF 4.0 only, not CTP5 (or now 4.1). This is simply because I need to have an architecture that is ready to ship to production in a few months and I’d rather rely on a more tried solution of a physical edmx and T4 POCO instead of code first.

    Anyhow, my question is, why are you using CreateQuery() instead of CreateObjectset() in your GenericRepository class? Wouldn’t it be more straightforward, and also you wouldn’t need to resolve the entity/container names?

    thanks, Zack

    • Hi Zack, thanks for your comment.

      Regarding the question, I thought each method has its own purpose, e.g. in the GetQuery() method I call ObjectContext.CreateQuery[TEntity](entityName) which returns exactly the desired IQueryable. But I haven’t acknowledged about the CreateObjectSet can be use in place of CreateQuery that somehow more convenient and shorter way to gain the same result. So you can use CreateObjectSet in stead of CreateQuery as long as you find it relevant.

      • Okay, that’s what I figured but just wanted to make sure I wasn’t missing something about CreateObjectSet() that would cause me not to want to use it.

        Another question, I am having a difficult time wrapping my head around how I would use ObjectContextStorage in a WCF environment.

        So basically my architecture is ASP.Net webform (service factory pattern for client proxy) -> WCF service -> Your Repository pattern -> EF 4 (with POCO T4) It seems like in this case, it doesn’t make sense to store the context, because it only is needed on demand upon activation of the WCF service. So basically I am creating and disposing the context in every WCF method. Is there a better way to do it? Like some sort of storage specifically for WCF service? If so, how would it perform in high volume transactional scenarios?

        Thanks again, Zack

      • Zack,

        In the context of Wcf, you may want to implement a WcfObjectContextStorage (or WcfDbContextStorage if you’re working with DbContext)

        In order to implement WcfXXXStorage, Sharp Architecture is a good source of reference because the idea to implement WebObjectContextStorage/WebDbContextStorage or SimpileObjectContextStorage/SimpleDbContextStorage in this framework is mostly inspired from it.

        In short, you can refer to Sharp Architecture and look for the WcfSessionStorare (SharpArchitecture uses NHibernate), but once you get the idea, you can implement it for ObjectContext/DbContext.

        Hope this helps.

  38. Are you planning on updating to EF4.1 anytime soon?
    I’ve already looked inside your “Lab” folder and it looks really promising.

    I will be waiting for your update.
    Thanks for your great contribution and keep up that good job.

  39. I have enjoy learning using you code sample. I have a quick question on writing inner joins. can you give a sample of using GetQuery().Where(x => x.Id == Id) and joining with about Object? Or is there a better way of doing it. I was thinking maybe query the first object then join to second one.

    Thanks,
    Seth

    • You can read LINQ to Entities tutorials for more information on join query, especially, the use of IQueryable. I think it needs a book, not just a sample one.

      Hope this helps.

      • i know how to write regular link join queries. I was looking to do more dynamic joins and maybe create something in the RepositoryBase like GetQueryWithJoin.

        Thanks.

  40. HI

    I have a class built MyContext: DbContext. Can you tell me how to integrate it with your Repository / UnitOfWork without using Reflection.
    I thank an example, please.

    Thanks.

    • Try this:

      MyContext context = new MyContext();

      IRepository repository = new Infrastructure.Data.EntityFramework.Lab.GenericRepository(context);

      // use the repository..

      –Hope this helps.

  41. How would you deal with one UnitOfWork for multiple repositories.

    I have situations where I need to insert data across several repositories and would like to save all the changes in one shot.
    With this implementation, I have to call:
    MyRepository1.UnitOfWork.SaveChanges();
    MyRepository2.UnitOfWork.SaveChanges();
    MyRepository3.UnitOfWork.SaveChanges();

    Thanks,
    Nelson Reis

    • I would use only one repository instead of multiple repositories. That said, all the operations that modifies data should be within a unit of work.

  42. How would you implement eager loading Huyrua?
    One approach would be to derive a new repository class(e.g. CustomerRepository) and add the method:
    public Customer GetCustomerWithProduct(int customerID)
    {
    GetQuery(x=>x.Id == customerID).Include(c => c.Products).ToList()
    }
    Is there any other approach?
    P.S. Any ETA on upgrading to EF 4.1?
    Thanks.

  1. Pingback: Entity Framework 4 POCO, Repository and Specification Pattern « ALT .NET Saigon's blog

Follow

Get every new post delivered to your Inbox.

Join 57 other followers

%d bloggers like this: