I have a database that uses a custom model for recording lookup valus (i.e. states, types, etc.). So across all of the database tables, there are various columns called something like state_cdv_id which would store an integer and reference the code_value table to get that state's value (i.e. "CA", "AK", etc.).
I would like to map my EF model so that I can access the code values for all of these fields, and I don't want to have to do it manually in partial classes for EVERY entity... that's a lot of repetition. So I want to be able to access my code values like: MyPerson.State and get back the string "CA" for example.
Here's what a single getter would be that I would have to repeat many times if I were to do it manually:
public string State
{
get
{
MyEntityContext c = new MyEntityContext();
return c.CodeValues.Single(cv => cv.Id == RecordStatusCdvId).Value;
}
}
I don't know what the best approach would be: change the T4 templates, add property attributes to certain fields and then programmatically add a getting to those, or something else.
Any help?
If there is a 1:1 relationship between the entity and the code_value table the entity should already have a State property, which by default which will be null by default, you could then fill it in by using an Include on your DB queries:
var foo = context.MyEntities.Include( x => x.State);
Your sample code is terribly wrong because it makes your entity dependent on the context (moreover you don't dispose it). Whole POCO approach just to avoid this (POCO T4 generator and DbContext T4 generator).
If you have relation to lookup table in your database EF will crate for you navigation property. If you don't have such relation in the database and you are using EDMX file you can still create such relation in your model and you will again get navigation property to lookup table. Once you have navigation property you can simply do:
string code = myEntity.State.Code;
But the navigation property must be loaded either by eager loading (as #BrokenGlass described) or by lazy loading.
If you don't like the idea of navigation property and you still want State property to show just code of the state you must understand what does it mean: If you map the entity that way it will be read-only because EF will not be able to transform compound entity back to real tables which must be updated. It is possible to map the entity the way you want but it is considered as advanced (and mostly not needed) scenario which works only if you have EDMX file (not with code first approach). The choices are:
Create database view and map the view to a new entity
Create DefiningQuery manually in EDMX (opened as XML) file and map it to a new entity (once you do that you cannot update your model from database or generate database from model any more)
Create QueryView manually in EDMX (opened as XML) file and map it to a new entity (this requires original entities to be already mapped)
You will have to do that for every table where you want such mapping. Anyway whole that complexity with manually changing EDMX is not needed because you can simply create custom classes like:
public class SomeViewModel // I suppose your main target is to have codes in presentation layer
{
public string SomeData { get; set; }
public string State { get; set; }
}
and use projection query
If you have navigation property:
var data = from x in context.SomeEntities
select new SomeViewModel
{
SomeData = x.SomeData,
State = x.State.Code
};
If you don't have navigation property
var data = from x in context.SomeEntities
join y in context.LookupValues on x.LookupId equals y.Id
select new SomeViewModel
{
SomeData = x.SomeData,
State = y.Code
};
Related
Let's suppose that we have this situation:
Tables in database:
Country (id, country_name), Person (id, login), CountryManager (id_country, id_person), CountryStakeholder (id_country, id_person)
If we had to create the model from the database, using Entity Framework Database-First, in VS we'd have a class like this:
class Country {
int id;
string country_name;
virtual ICollection<Person> Person1; // Navigation Properties
virtual ICollection<Person> Person2; // ---------||----------
}
I've simplified the code a lot, but hopefully you got the point.
Seems that when Entity Framework deals with foreign keys it creates generic Navigation Properties. Is there a possibility to control how Navigation Properties are created by name? Person1, Person2 isn't very explainatory, unfortunately.
In VS you can do this with the GUI.
If you show Model Browser then navigate down the tree to:
YourEntityModel > Entity Types > Country
then right-click on the "Person1" Navigation Property and select "Properties" you can then change the name of the navigation property name to whatever you like:
Just change the name, save changes and your done...
(Actually there are lots of ways to get to the Navigation Property properties window - you cn right click on it in the model diagram too)
From the entry "Working with Inverse Navigation Properties" from the book "Programming Entity Framework: Code First":
You can add configuration (using Data Annotations or the Fluent API)
to present this information to the model builder. With Data
Annotations, you’ll use an annotation called InverseProperty. With the
Fluent API, you’ll use a combination of the Has/With methods to
specify the correct ends of these relationships.
You can place the annotations on either end of the relationship (or
both ends if you want). We’ll stick them on the navigation properties
in the Lodging class (Example 4-10). The InverseProperty Data
Annotation needs the name of the corresponding navigation property in
the related class as its parameter.
Example:
[InverseProperty("PrimaryContactFor")]
public Person PrimaryContact { get; set; }
[InverseProperty("SecondaryContactFor")]
public Person SecondaryContact { get; set; }
I recommend using https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838
It allows more flexibility than any database generation thing I've seen.
I'm still working on solving my own problem, but this looks pretty promising. But, unlike the Default Code generation that EF provides, you can customize the mapping.
Like, in all the examples I've seen on renaming the navigation properties -- that alone won't be enough, because EF still needs to be mapped to use those navigation properties (you could hack it though, and have your User2 point to ModifiedByUser, for example).
I have a mvc 4 application which is entity framework database first based. Therefore lots of the classes are generated based on database tables via EF.
Currently, I created a method to retrive data from a table and display them in a dropdownlist, which works fine. However, I am thinking to modify that method to a generic type method, and passing the class type as the method parameter, and I would like c# code to find the mapping table in the database and retrive the data.
Following is my modified method
Thanks for your helps!
public static SelectList FromDbTableToSelectList<T>() where T: class
{
var db = new TableEntities();
//find the mapping database table
Dictionary<Guid, string> dic = db.MappingTable.ToDictionary(v => v.tableColumn1, v => v.tableColumn2);
return new SelectList(dic, "Key", "Value");
}
I don't understand your what your code does. However, there is a trick to find mapping table name (Entity Set Name in EF glossary) of an entity.
Suppose that you have a table in your db named Products. If you create your model with the Pluralize and singularize option checked, EF will create an entity class named Product.
Then, whenever you perform a query, EF naming convention thinks that your table name is dbo.Products. This is a general rule - in fact a naming convention.
From the other hand, if you uncheck the Pluralize and Singularize option, EF creates an entity class named Products for you and in this case, the class an the table have same names.
So, according to the selection of P&S option, you can infer table names from entity names and you don't need any code for it...
Scenario:
As mentioned here, once you add additional properties to a simple join table (many-to-many relationship), it's no longer a hidden association. These questions also address this:
Many-to-Many relationship in Entity Framework with relationship informantion
How can I add properties to an association (relationship) using the Entity Framework
The existing code already uses the simple, automatically hidden navigation properties, and there are some minor customizations to the autogenerated tables, and so I'd like to avoid refactoring the entire project when I alter the underlying relationship table.
Question:
Is there a way so that both the automatic navigation (many-to-many) accessors can remain, but I can also access the relationship entity directly?
I could just write my own accessors selecting from the relationship table, but then they're no longer EntityCollections and thus I'm concerned that I lose whatever magic happens under the hood like tracking, etc.
Can I manually add EntityCollections to entities?
Expectation:
Originally: Product* <-> *Offer
a Product has many Offers (like 50% off, BOGO)
the same Offer could apply to many Products ("Red Shirt" and "Blue Pants" are BOGO)
Desired: Product* <-[sort]-> *Offer
When I list Offers for a Product, I can sort them independently
i.e. "Red Shirt" has "50% off" then "BOGO", but "Blue Pants" shows "BOGO" then "50% off"
then I would want to be able to do:
// original access, do stuff
List<Offer> applicableOffers = currentProduct.Offers.Where(...);
// hit up the join table directly for properties
var applicableOffersInOrder = applicableOffers.OrderBy(o => o.ProductOffers.Sort);
rather than
var applicableOffersInOrder = currentProduct.ProductOffers
.OrderBy(o => o.Sort)
.Offers.Where(...);
I think the easiest way to do it is simply add two properties manually in a non-autogenerated partial class:
partial class Offer
{
public IQueryable<Product> Products
{
get { return this.ProductOffers.Select(x => x.Product); }
}
}
partial class Product
{
public IQueryable<Offer> Offers
{
get { return this.ProductOffers.OrderBy(x => x.Sort).Select(x => x.Offer); }
}
}
This won't help for when you want to add a new ProductOffer, but since you actually have extra data (Sort) you should be doing that via the ProductOffers collection anyway.
I am using entity framework, code first, 4.0, hitting an existing legacy database for read-only access. The database is normalized, so
Table [Event]
[ID]
[Date_Entered]
[Event_Status_Key]
Table [Event_Status]
[Event_Status_Key]
[Event_Status_Description]
My class looks like
public class Event
{
public DateTime DateEntered { get; set; }
public string StatusDescription { get; set; }
}
This is a WCF service layer application.
My two questions:
Is there any easy way to populate the status description without creating a second Dictionary-type object? I've seen questions like this: Entity Framework Mapping to Lookup table, but they seem to be focused on object to object, and I really just want a primitive. I'd prefer using the fluent API as opposed to attributes.
When the data is loaded, is any of the data cached at the code layer? Or does each check on the StatusDescription mean a separate call on the [Event_Status] table?
Edit: A possible (more subjective, which is why I didn't bring it up) third question is how close should the data entities match the database. Is it always a one-to-one field/table? Is what I'm doing (joining two tables into one data entity obejct) bad?
Thanks.
Entity framework expects that you will map both tables as separate entities and use projection in your query:
var query = from e in context.Events
select new WcfEvent // Your original Event class is just DTO
{
DateEntered = e.DateEntered,
StatusDescription = e.EventStatus.EventStatusDescription
};
This example expects correctly one-to-one mapping of your Event and Event_Status tables.
If you need any kind of caching you will have to implement it yourselves. Projected results are not even tracked by the context.
I'm using Entity Framework 4.1. I have a normal model .edmx which maps a Match class to a 'Match' database table and this can be accessed as normal using EF.
However I require custom properties methods for the Match so I extended this using a partial class and I can add my properties etc.
All of this works fine, however I just can't find out how to instantiate an instance of my partial match class by its primary key / id. i.e so I can pass the Id into the constructor and have the object populated with all of its data from the database.
I know we can do the following to populate from calling code:
public Match PopulateforMatchId(int matchId)
{
var match = (from m in _db.Matches
.Include("TeamA")
.Include("TeamB")
.Include("Season")
.Include("Season.Competition")
where m.Match_ID == matchId
select m).FirstOrDefault();
return match;
}
However this is not what I need as this is not self contained within the partial class itself, I need it to populate itself, as other properties in the partial class rely on the object itself having its data in place before they can be calculated.
Anyone have any ideas how i can do this?
Thanks
Kevin
This is wrong way to use Entity framework. Entity framework is not suitable for easy populating existing object. Moreover it demands that entity has internal dependency on the EF context.
How to probably make it work (but I definitely not recommend it):
public Match(int matchId)
{
// You called constructor yourselves = you have unproxied entity without
// dynamic change tracking and without lazy loading
Id = matchId;
// I'm not sure if this is possible in entity constructor but generally it should work
// Get context somewhere - service locator pattern
ObjectContext context = ContextProvider.GetCurrent();
context.Matches.Attach(this);
context.Refresh(RefreshMode.StoreWins, this);
// Now you should have populated Match entity itself but not its navigation properties
// To populate relations you must call separate query for each of them because `Include`
// is possible only when the entity is created and loaded by EF and lazy loading is off
// in this case
context.LoadProperty(this, m => m.TeamA);
context.LoadProperty(this, m => m.TeamB);
Season = (from s in context.Seasons.Include("Competition")
select s).ToList();
}
This is also the example of wrong constructor - constructor should not take such heavy logic. It should be responsibility of some other initialization method.