New version of EFProviderWrappers released

EFProviderWrappers sample for Entity Framework has been updated to support new features in EFv4 and Visual Studio 2010:

Changes in this release since 3.5SP1 version:

  1. Upgraded all projects to .NET 4.0 and retargetted assemblies to use .NET Framework 4 Client Profile
  2. Removed reflection-based code to invoke CreateCommandDefinition()
  3. Moved AspNetCache to a separate assembly (which depends on .NET Framework 4 Extended Profile)
  4. Added wrappers for new provider API surface of DbProviderManifest class:
    • bool SupportsEscapingLikeArgument(out char escapeCharacter)
    • string EscapeLikeArgument(string argument)
  5. Added wrappers for new provider API surface of DbProviderServices class:
    • void DbCreateDatabase(DbConnection connection, int? commandTimeout, StoreItemCollection storeItemCollection);
    • bool DbDatabaseExists(DbConnection connection, int? commandTimeout, StoreItemCollection storeItemCollection);
    • void DbDeleteDatabase(DbConnection connection, int? commandTimeout, StoreItemCollection storeItemCollection);
    • string DbCreateDatabaseScript(string providerManifestToken, StoreItemCollection storeItemCollection);
  6. Wrappers now work in partial trust – check out AspNetCachingDemo
  7. Removed Velocity adapter and demo.
  8. Recreated sample models using edmx (instead of explicit csdl/ssdl/msl)
  9. Removed the need to explicitly install the database in SQL Server – instead using |DataDirectory| and mdf files local to the project.

The sample can be downloaded from MSDN Code Gallery.

Tags: , ,

  1. #1 written by Shawn April 30th, 2010 at 08:15

    Jarek, I’m assuming I need to either install a DB or update a config to point to the DB, because when I attempt to run I get a connectivity error. Is there a readme with installation instructions? Or can you simply tell me what I need to do? Thanks so much!

    RE Q
  2. #2 written by Jarek Kowalski April 30th, 2010 at 11:11

    The new package comes with SQL database files which should automatically attach to local SQLEXPRESS instance. What error are you seeing?

    RE Q
  3. #3 written by Scott L. Mitchell May 3rd, 2010 at 16:49

    Have you (or anyone that you know) experimented with memcached using this approach? We are locked into memcached as a distributed cache provider.

    Could you point me in the right direction to DIY?

    Best,
    == slm ==

    RE Q
  4. #4 written by Jarek Kowalski May 3rd, 2010 at 19:30

    Previous version supported Velocity CTP and used very simple get/put interface, which I think is also supported by memcached. Handling invalidation for dependencies can be a bit more complex, but should be doable with memcached. You can start with the old version at http://code.msdn.microsoft.com/EFProviderWrappers/Release/ProjectReleases.aspx?ReleaseId=2819 which includes Velocity sample.

    RE Q
  5. #5 written by Scott L. Mitchell May 4th, 2010 at 10:34

    Thanks a million! I’ll post what I come up with.

    RE Q
  6. #6 written by Joris May 11th, 2010 at 04:56

    I tried to build the project, but I get the following error (I’m using framework 4.0):
    ‘EFProviderWrapperToolkit.DbProviderServicesBase.DbCreateDatabase(System.Data.Common.DbConnection, int?, System.Data.Metadata.Edm.StoreItemCollection)’: no suitable method found to override

    What could be the problem?

    RE Q
  7. #7 written by Jarek Kowalski May 11th, 2010 at 07:07

    Are you using the final version of Visual Studio 2010 RTM? If so, make sure that project is set to target .NET Framework 4.0 and not 3.5.

    RE Q
  8. #8 written by Joris May 13th, 2010 at 08:42

    I’m still using VS 2010 Beta 2. So I will install the final version and see if that resolves the problem. Thank you for your reply.

    RE Q
  9. #9 written by jackiedigital May 18th, 2010 at 00:24

    Great work!!!
    I’ve downloaded sample, but I’m getting “NotImplementedException – at EFCachingProvider.EFCachingDataReaderCacheWriter.GetName(Int32 ordinal)” when i try to add Order to Customer in EFProviderWrapperDemo.CacheInvalidationDemo(). Exception is thrown when calling SaveChanges()

    StackTrace:
    at EFCachingProvider.EFCachingDataReaderCacheWriter.GetName(Int32 ordinal) in D:\code samples\EFWrapperDemo\EF4ProviderWrappers\EFCachingProvider\EFCachingDataReaderCacheWriter.cs:line 109
    at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary`2 identifierValues, List`1 generatedValues)
    at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)

    Modifed demo method:

    private static void CacheInvalidationDemo()
    {
    var cache = new InMemoryCache();

    // log SQL from all connections to the console
    EFTracingProviderConfiguration.LogToConsole = true;

    for (int i = 0; i c.CustomerID == “ALFKI”);
    Console.WriteLine(“Customer name: {0}”, cust.ContactName);
    cust.ContactName = “Change” + Environment.TickCount;
    Console.WriteLine(“Loading orders…”);
    cust.Orders.Load();

    Console.WriteLine(“Order count: {0}”, cust.Orders.Count);
    var neworder = context.Orders.CreateObject();

    neworder.CustomerID = cust.CustomerID;
    neworder.EmployeeID = context.Employees.FirstOrDefault().EmployeeID;

    var orderDetails = context.OrderDetails.CreateObject();
    orderDetails.Discount = 1;
    orderDetails.ProductID = context.Products.FirstOrDefault().ProductID;
    orderDetails.Quantity = 12;
    orderDetails.UnitPrice = 2;

    neworder.OrderDetails.Add(orderDetails);
    neworder.ShipAddress = “address”;
    neworder.ShipCity = “city”;
    neworder.ShipCountry = “country”;
    neworder.ShipName = “shpname”;
    neworder.ShipPostalCode = “222222″;
    neworder.ShipRegion = “shipRegion”;

    cust.Orders.Add(neworder);

    context.SaveChanges();
    }
    }

    Console.WriteLine();
    }

    RE Q
  10. #10 written by boka dunko June 1st, 2010 at 02:30

    Really nice work!

    I’am using your sample EFProviderWrapperDemo,
    but every time i try to create more then one Order in your CacheInvalidationDemo() function from the sample, i get the exception “NotImplementedException – at EFCachingProvider.CachingDataReaderCacheReader.GetName(Int32 ordinal)”.

    the sample code is:

    using (var context = new ExtendedNorthwindEntities())
    {
    // set up caching
    context.Cache = cache;
    context.CachingPolicy = CachingPolicy.CacheAll;

    //Console.WriteLine(“Loading customer…”);
    var cust = context.Customers.First(c => c.CustomerID == “ALFKI”);

    var order = new Order();
    order.OrderDate = DateTime.Now;
    cust.Orders.Add(order);

    var order2 = new Order();
    order2.OrderDate = DateTime.Now;
    cust.Orders.Add(order2);

    context.SaveChanges();
    }

    I think there is a bug in EfCachingCommand.ExecuteDbDataReader function!
    The orders in this sample are created with same parameters(but primary key is different of course).
    So the query’s generated from the ef4 for those two objects are actually the same: one insert sql, and one select sql to retrive new order from db with new id.

    When ExecuteDbDataReader is called to create the second order2 in db, the first order object is already cached with the same key/query, and instead to create a new order2 object in db, function is actually trying to read it from the cache. That is way execution goes to the EFCachingProvider.CachingDataReaderCacheReader.GetName(string name) function…

    I tried to fix it by not caching the queries containing the call to scope_identity() sql server function(so it will execute dbDataReader), and it seems it works.
    Maybe it would be better to put the “SqlServer.SCOPE_IDENTITY” string in NonCacheableFunctions hashtable (in that way IsCacheable() would return false).
    But I can’t see how you fill “functionsUsed” property, it is empty when i go with debuger? or i am missing something?

    RE Q
  11. #11 written by Jarek Kowalski June 1st, 2010 at 06:59

    @boka

    Thank you for your feedback, I really appreciate it. I’ll see if I can find a fix for this issue.

    RE Q
  12. #12 written by Shane Simpkins June 23rd, 2010 at 03:01

    Any progress at all towards fixing the issue where ‘NotImplementedException’ is thrown when calling ‘SaveChanges()’ on a data context?

    > Same issue that @boka mentioned!

    Thanks in advance!

    RE Q
  13. #13 written by Dinesh July 19th, 2010 at 00:32

    Jarek, I’d like to echo the previous poster and ask, are there any updates on this? I have done some digging around and here are my findings.

    I get the have incorporated the EFCachingProvider into a test project and I get the same exception that Boka mentioned – in the EFCachingProvider.CachingDataReaderCacheReader.GetName(string name) method.

    However I get it on update statements. The problem is more or less the same – the key that is getting passed into the Cache is the SQL update statement without the parameters replaced for their values. So on the second update the EFCachingCommand ends up treating it as a cached query (because of a cache hit match) and ends up creating a CachingDataReaderCacheReader instead of a EFCachingDataReaderCacheWriter.

    I tracked the bug down to the GetCacheKey method – the following line looks wrong:

    sb = sb.Replace(“@” + parameter.ParameterName, GetLiteralValue(parameter.Value));

    Because the parameter name contains the “@” character. So it tries to match “@@paramName” which it of course doesn’t, hence the cache key stays as is. I replaced this line with the following:

    string token = parameter.ParameterName.StartsWith(“@”)
    ? parameter.ParameterName
    : “@” + parameter.ParameterName;

    sb = sb.Replace(token, GetLiteralValue(parameter.Value));

    And it now works.

    However, I question whether Update and Insert commands should be cached at all. Is it straightforward to determine purely from the command text whether it’s an update or insert. Maybe if the command text contains “insert” or “update” (before parameter value replacement) it should simply not be cached.

    RE Q
  14. #14 written by Dinesh July 19th, 2010 at 02:19

    Following up on my previous comment, I would make this suggestion:

    Modify the EFCachingCommandDefinition.IsCacheable() method to be:

    public bool IsCacheable()
    {
    if (this.IsModification)
    {
    return false;
    }

    if (this.functionsUsed.Any(f => IsNonDeterministicFunction(f)))
    {
    return false;
    }

    return true;
    }

    The change is addition of the “if (this.IsModification) { return false; }” part. Basically, if the command contains an insert, update or delete, it should not be cached. But since it ends up making a database change to data that may already have been cached, that data cache still needs to be invalidated.

    Do you agree?

    RE Q
  15. #15 written by Metalex August 9th, 2010 at 14:56

    Hello, what about support for stored procedures used for entities persistence? If I try to use them I get an exception.

    RE Q
  16. #16 written by Wendy S August 11th, 2010 at 09:05

    I am using the EF4ProviderWrappers with an InMemoryCache. I’ve found that after doing an insert, update or delete I have to invoke cache.InvalidateSets. If I don’t do this I get the wrong data back. I’ve kept an eye on the cache stats and it seems that no invalidations happen automatically. Is it correct that I have to do this manually?

    RE Q
  17. #17 written by Wendy S August 26th, 2010 at 07:14

    The problem was with transactions like so
    using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.RequiresNew))

    Instead use
    DbTransaction transaction = context.Connection.BeginTransaction();

    and the invalidations work as expected

    RE Q
  18. #18 written by Vijendra September 21st, 2010 at 06:26

    Hi Jarek,

    I was looking at the EFPocoAdapter. I am finding little difficulties in updating the Foreign Key of a table.

    I have 2 entity. (Bug (*-1)Module)

    Bug { int BugID, string Synopsis, Module ModuleRef}
    Module{int ModuleID, string ModuleName, List BugCollectionRef}

    Now whenever i need Bug entity i do.

    var bug = context.Bug.First(b => b.BugID == bugID);
    context.LoadProperty(bug, “Module”);

    /*
    If i say context.Bug.Detach(), the loaded Module property gets set to Null, so i dont detach the bug object
    */

    Now when i try to update the Module, say if i want to set the module of a Bug from “Test Module” to “New Module”, i am not able to do it. I am writing following code.

    var updatedBugObject = context.Bug.First(b => b.BugID == bugID);
    context.LoadProperty(updatedBugObject , “Module”);
    updatedBugObject.Module = GetNewModule(“New Module”);

    var originalBug = context.Bug.First(b => b.BugID == bugID);
    context.LoadProperty(originalBug , “Module”);
    context.Bug.Attach(originalBug);
    context.Bug.ApplyPropertyChanges(updatedBugObject);
    context.SaveChanges();

    How do i update the Foreign key.

    Though the original table Bug has FK moduleID defined , but when you associate a relation using Entity Framework, the EF designer asks you to Delete the “ModuleID” scalar property from the Bug entity, as the ModuleID can be accessed through the “ModuleRef” navigation property of the Bug Entity.

    Please let me know how to update the Foreign Key using the EFPocoAdapter for 1-* entity.

    Thanks,
    Vijendra

    RE Q

SetPageWidth