Background:
I have a Web API project and a Class Library project in the same solution that share the same Model classes. Both projects share the same database and both use DbContext to read/write data.
The Web API project is set up in the typical UnitOfWork pattern and works just fine.
The class project is a bit different. I specify the connection string in the constructor instead of the Web.config file:
class MyContext : DbContext
{
public MyContext(string connectionString)
: base()
{
// Do this to force me to use eager loading
this.Configuration.LazyLoadingEnabled = false;
// Init connection string
this.Database.Connection.ConnectionString = connectionString;
Database.SetInitializer <CFCalcContext> (null);
}
... DbSets ...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
... modelBuilder details ...
}
}
I use the Web API to call a function defined in the class library. When I attempt to query the database using the class library I get an error.
The Problem:
In the class library project I get a EntityCommandCompilationException with the inner exception as:
InnerException: System.Data.MappingException
HResult=-2146232032
Message= (82,10) : error 3034: Problem in mapping fragments starting at lines 82, 90:Two entities with different keys are mapped
to the same row. Ensure these two mapping fragments do not map two
groups of entities with different keys to the same group of rows.
(82,10) : error 3034: Problem in mapping fragments starting at lines
82, 98:Two entities with different keys are mapped to the same row.
Ensure these two mapping fragments do not map two groups of entities
with different keys to the same group of rows.
(82,10) : error 3034: Problem in mapping fragments starting at lines
82, 106:Two rows with different primary keys are mapped to the same
entity. Ensure these two mapping fragments do not map two groups of
entities with identical keys to two overlapping groups of rows.
(82,10) : error 3034: Problem in mapping fragments starting at lines
82, 112:Two entities with different keys are mapped to the same row.
Ensure these two mapping fragments do not map two groups of entities
with different keys to two overlapping groups of rows.
(82,10) : error 3034: Problem in mapping fragments starting at lines
82, 118:Two entities with different keys are mapped to the same row.
Ensure these two mapping fragments do not map two groups of entities
with different keys to two overlapping groups of rows.
(90,10) : error 3034: Problem in mapping fragments starting at lines
90, 98:Two entities with different keys are mapped to the same row.
Ensure these two mapping fragments do not map two groups of entities
with different keys to the same group of rows.
Also, when I right click the derived DbContext class (in the class library) and use Entity Framework Power Tools to "View Entity Data Model" I get the error: "A constructible type deriving from DbContext could not be found in the selected file." This works just fine in the Web API project.
Why would two DbContexts that connect to the same database and are configured basically the same perform differently? I must be missing a configuration step, but I don't know which.
Thanks for the help!
A lot going on here. Firstly, if you're manually setting the connection string you should be setting it in the call to the base constructor:
public MyContext(string connectionString)
: base(connectionString)
Secondly though, you should really be putting that in Web.Config - if the name is the issue, you can give it a different name like:
public MyContext()
: base("Whatever name I used in Web.Config")
Third this is probably just wrong:
Database.SetInitializer <CFCalcContext> (null);
The documentation for Database.SetInitializer states:
Gets or sets the database initialization strategy. The database initialization strategy is called when DbContext instance is initialized from a DbCompiledModel.
In other words setting it to null is likely to make your DbContext explode as soon as it tries to do anything - I suspect that's what's happening to you here.
Related
I am developing MVC application and using razor syntax. I have used model first method.
I have two entities, Customer and Lead. Lead is inherited from Customer.
When IsActive property is true then Customer treated as a Lead, otherwise it will be a customer.
Please check edmx file image.
Now, In regular entities we just deal with single entity and single table.
In this case how can I handle , Save and Load process. beacuse I have to store and load the record from 2 tables of DB.
Is Regular Index View will work here ?
When using inheritance in the Entity Framework you will have a single DbSet on your DbContext that exposes your hierarchy. In your database you have several options for configuring your table structure. For example you can use:
Table per Hierarchy
Table per Type
Table per Concrete type
(See this blog for a nice explanation: Inheritance in the Entity Framework.
In your queries however, you don't have to think about this. Your queries will have the following structure:
var leads = from l in dbcontext.Leads.OfType<Customer>()
select l;
The OfType() filters your collection to a subtype in your hierarchy. If you skip the OfType you will get both customers and leads in your resulting query.
I'm new to the whole ASP world and I'm getting my feet wet by building a C# MVC3/EF4 project. I'm finding it hard to keep from duplicating a bunch of code in my models and view models. Consider an object Foo. I need to do the following things with Foo:
Store records of type Foo in my database.
Allow users to lookup records of an individual Foo (pass instances of Foo to a view).
Allow users to create new instances of Foo (pass instances of Foo to a form).
Let's say I also have a type Bar. A Bar contains a list of Foos. There are two requirements here:
Users can view a list of Bars.
When the user clicks on a specific Bar, it shows all of its Foos.
So, a sketch of my basic objects look like this:
class Foo
{
string FooName;
int Id;
}
class Bar
{
List<Foo> FooList;
int Id;
string Baz;
}
But when I start thinking about the different views, it begins to get messy:
The views shouldn't have any write access to any of the data members.
There's one view that takes a list of Bars but doesn't care about Bar.FooList. Let's say I also want to be good about resource management and close the DbContext as soon as possible (i.e. after the object is in memory but before I render the view). If I just pass it a list of Bars and the designer tries to access the FooList by mistake, we'll get a runtime error. Yuck!
Ok fine, I just create a distinct ViewModel for each view that has read only datamembers, no problem.
But both the database model and the form models will need to have DataAnnotations attached which say which fields are required, max length of the strings, etc. If I create separate form models and database models then I end up having to duplicate all these annotations. Yuck!
So, that's my architectural dilemma: I want to have succinct view models which restrict the views only to reading the data they are supposed to access. I want to avoid repeating data annotations all over the place. And I want to be able to aggressively free my DB resources as soon as possible. What's the best way to achieve my goals?
My advice is do NOT use data annotations in your EF entity classes. Instead, try out the fluent API. It keeps persistence concerns out of the model classes themselves. You can even define the modelbuilder stuff in an entirely different library.
As for having duplicate properties, properties are cheap:
public string MyProp { get; set; }
Not a lot of code, and you may begin to see, the viewmodels and entities need not always be exact duplicates of each other. For example, what if you want to apply [HiddenInput] to a viewmodel, to get it to render as <input type="hidden" />? Would you apply that to the entity? Why? It belongs in the viewmodel (the namespace is even System.Web.Mvc, not System.ComponentModel.DataAnnotations).
As far as duplicating error messages during validation (if you validate the MVC and EF layers separately), you can use resx resources.
As far as freeing db resources, let EF manage that. I find it's best to keep a single DbContext instance per HttpContext. You can open it up using a factory, an OnActionExecuting action filter, Application_BeginRequest, with an IoC container, or whatever. Then dispose context during OnResultExecued, Application_EndRequest, etc. Keeps things simple.
I have an entity (Org) in my Entity Framework that has a foreign key with a table that is in another database (BusinessUnit). We need the foreign key to get the description of the BusinessUnit linked with the Org. In the past (old project without Entity Framework) we were using a stored procedure to return all the information about this entity, including the BusinessUnit description, using a join. So now my problem is how to display the same information than before using Entity Framework.
I've tried, once I load my Org entity from database, to make a loop accessing to BusinessUnit to get the description for each Org, but this is too slow. My other idea was use a store procedure, but I need an extra field on my entity and Entity Frameworks gives me an 3004 error: No mapping specified for my property. I was thinking to use a complex type, but I'm not sure if it's what I need keeping in mind I have to add just a field to my entity. In that case, could I use the complex type just for "select" operations and keep my original entity for the rest of CRUD operations?
How should I proceed?
Thanks.
EF is not able to execute queries across multiple databases. If you need to perform such query you must either use database view and map the view as a new entity (it will be readonly - making it updatable requires mapping insert, update and delete stored procedures) or divide your data querying into two separate parts to load data from both databases. Divided querying can either use two contexts or you can get data from the second database using stored procedure.
The reason why you got the error is that you added the property in EDMX. EDMX can contain only properties mapped to your first database. EDMX generates entity code as partial classes If you need property manually populated from the second database you have to create your partial part (partial class) for entity and add the property in code.
My current setup:
I have an entity object with some properties, among them an int Id. To communicate with the database, I've created a repository with, among others, the following method:
public int Add(TEntity entity)
{
ObjectSet.AddObject(entity);
return entity.Id;
}
(It's a generic repository, that requires that TEntity is a class, and that it implements IEntity, which is just an interface with an int Id property.)
My problem:
Now, when I want to create a new entity for adding to the repository, I need to give it an id. However, that doesn't allow EF to automatically generate the id for me, since it will already have a value.
Possible solutions:
I have only been able to think of these two possibilities.
Make the Id property nullable
Pass an EntryInputModel to the repository instead, and then do the mapping there.
Currently I'm binding to EntryInputModel in my Controller, and mapping it to an Entry using AutoMapper. If I need to change this, I also need to re-think the dependencies in my project, since the ...InputModel and ...ViewModel classes are currently only available to my Web application.
Which is preferable? Are there more ways to counter this?
If you're using SQL Server as the backend, my recommended solution would be to make the ID column an INT IDENTITY on the database, and a not-nullable column in your entity object.
When adding a new entity, assign the ID some arbitrary value, like -1 or something, or no value at all, even. The actual ID will be generated automatically by SQL Server when you insert the new entity (
EntityContext.AddToEntities(newEntity);
EntityContext.SaveChanges();
and it will be automagically be signalled back to EF so you'll be able to use it right away once it's inserted:
int newEntityID = newEntity.ID;
Works like a charm - at least in my test apps :-)
you can have generated unique id's that are not generated by the datastore/EF, allowing you to define them before passing the object into EF... (think of Guid's)
Let's start with this basic scenario:
I have a bunch of Tables that are essentially rarely changed Enums (e.g. GeoLocations, Category, etc.) I want to load these into my EF ObjectContext so that I can assign them to entities that reference them as FK. These objects are also used to populate all sorts of dropdown controls. Pretty standard scenarios so far.
Since a new controller is created for each page request in MVC, a new entity context is created and these "enum" objects are loaded repeatedly. I thought about using a static context object across all instances of controllers (or repository object).
But will this require too much locking and therefore actually worsen perf?
Alternatively, I'm thinking of using a static context only for read-only tables. But since entities that reference them must be in the same context anyway, this isn't any different from the above.
I also don't want to get into the business of attaching/detaching these enum objects. Since I believe once I attach a static enum object to an entity, I can't attach it again to another entity??
Please help, I'm quite new to EF + MVC, so am wondering what is the best approach.
Personally, I never have any static Context stuff, etc. For me, when i call the database (CRUD) I use that context for that single transaction/unit of work.
So in this case, what you're suggesting is that you wish to retrieve some data from the databse .. and this data is .. more or less .. read only and doesn't change / static.
Lookup data is a great example of this.
So your Categories never change. Your GeoLocations never change, also.
I would not worry about this concept on the database/persistence level, but on the application level. So, just forget that this data is static/readonly etc.. and just get it. Then, when you're in your application (ie. ASP.NET web MVC controller method or in the global.asax code) THEN you should cache this ... on the UI layer.
If you're doing a nice n-tiered MVC app, which contains
UI layer
Services / Business Logic Layer
Persistence / Database data layer
Then I would cache this in the Middle Tier .. which is called by the UI Layer (ie. the MVC Controller Action .. eg. public void Index())
I think it's important to know how to seperate your concerns .. and the database stuff is should just be that -> CRUD'ish stuff and some unique stored procs when required. Don't worry about caching data, etc. Keep this layer as light as possible and as simple as possible.
Then, your middle Tier (if it exists) or your top tier should worry about what to do with this data -> in this case, cache it because it's very static.
I've implemented something similar using Linq2SQL by retrieving these 'lookup tables' as lists on app startup and storing them in ASP's caching mechanism. By using the ASP cache, I don't have to worry about threading/locking etc. Not sure why you'd need to attach them to a context, something like that could easily be retrieved if necessary via the table PK id.
I believe this is as much a question of what to cache as how. When your are dealing with EF, you can quickly run into problems when you try to persist EF objects across different contexts and attempt to detach/attach those objects. If you are using your own POCO objects with custom t4 templates then this isn't an issue, but if you are using vanilla EF then you will want to create POCO objects for your cache.
For most simple lookup items (i.e numeric primary key and string text description), you can use Dictionary. If you have multiple fields you need to pass and back with the UI then you can build a more complete object model. Since these will be POCO objects they can then be persisted pretty much anywhere and any way you like. I recommend using caching logic outside of your MVC application such that you can easily mock the caching activity for testing. If you have multiple lists you need to cache, you can put them all in one container class that looks something like this:
public class MyCacheContainer
{
public Dictionary<int, string> GeoLocations { get; set; }
public List<Category> Categories { get; set; }
}
The next question is do you really need these objects in your entity model at all. Chances are all you really need are the primary keys (i.e. you create a dropdown list using the keys and values from the dictionary and just post the ID). Therefore you could potentially handle all of the lookups to the textual description in the construction of your view models. That could look something like this:
MyEntityObject item = Context.MyEntityObjects.FirstOrDefault(i => i.Id == id);
MyCacheContainer cache = CacheFactory.GetCache();
MyViewModel model = new MyViewModel { Item = item, GeoLocationDescription = GeoLocations[item.GeoLocationId] };
If you absolutely must have those objects in your context (i.e. if there are referential entities that tie 2 or more other tables together), you can pass that cache container into your data access layer so it can do the proper lookups.
As for assigning "valid" entities, in .Net 4 you can just set the foreign key properties and don't have to actually attach an object (technically you can do this in 3.5, but it requires magic strings to set the keys). If you are using 3.5, you might just try something like this:
myItem.Category = Context.Categories.FirstOrDefault(c => c.id == id);
While this isn't the most elegant solution and does require an extra roundtrip to the DB to get a category you don't really need, it works. Doing a single record lookup based on a primary key should not really be that big of a hit especially if the table is small like the type of lookup data you are talking about.
If you are stuck with 3.5 and don't want to make that extra round trip and you want to go the magic string route, just make sure you use some type of static resource and/or code generator for your magic strings so you don't fat finger them. There are many examples here that show how do assign a new EntityKey to a reference without going to the DB so I won't go into that on this question.