I'm working with EF 4.1 CTP5 and SQL Server 2008. I need to understand how to solve a recurrency problem. I have the following 2 classes:
public class Nation
{
public int ID {get; set;}
public string name {get;set;}
public List<NationAlly> NationAllies {get;set;}
}
public class NationAlly
{
public int ID {get; set;}
public int level {get;set;}
public Nation Owner {get; set;}
public Nation toNation {get;set;}
}
The entities are mapped to the database with two tables (Nations and NationAllies). Besides, there are two relationships. 1) From NationAllies.OwnerID to Nation.ID
2) From NationAllies.ToNationID to Nation.ID
When I try to retrieve an object of Nation type from my database, I access the DbContext class NationDB:
Nation selectedNation = ((nationDB.Nations.Include("NationAllies")).Where(m => m.name == "France")).FirstOrDefault();
The problem is that I get a selectedNation object which has a list of NationAllies but every NationAlly in the list has the field toNation = null.
First of all I would like the field toNation to retrieve the correct information from the database. How do I do this?
Then of course toNation will be connected with other NationAllies which on their turn will have an other Nation. How could possibly a recursive map be built? My idea is to navigate the map until a certain level, by querying the database in a specific way. Doing so, what would be the best approach to have good speed performance?
It looks like NationAllies is junction table with additional properties. The problem is that EF doesn't eager load nested navigation properties if you do not specify them explicitly in Include method. If you want to have toNation filled you must use
nationDB.Nations.Include("NationAllies.toNation")
or
nationDB.Nations.Include(n => n.NationAllies.Select(na => na.toNation))
You can also enable lazy loading. Make all your navigation properties virtual (toNation, NationOwner and NationAllies) and unless you close the context all properties will be loaded once you first access them.
Related
I have table that has these columns:
Id
Title
Description
CreateDateTime
CategoryId
Picture
quantity
Price
RentPrice
WantToExchange
NumberOfRoom
DepositPrice
Only the first 6 are required for each row and other column will be null based on entity category.
For example in cat1 only first 6 field and Price filled by user,and in cat2 only first 6 field and RentPrice, DepositPrice are filled, so after a while many column of table rows become a null
I see some solution in NopCommerce source code that used for store various product property in different language - there are entity called LocalizedProperty and storeEntityId, LanguageId, Name of entity, name of field and its value
it use
Expression<Func<T, TPropType>>
and PropertyInfo to get name of field, but I am searching for an easier way.
How can I redesign my entity?
If you'd have designed this object orientedly, you would probably have create a PictureDescription class, and a PicturePrice class, that would have the other properties.
Every PictureDescription would have zero or one PicturePrice object: a straightforward aggregation
If you want zero-or-one in a relational Database, then this is quite often done using two tables, with a foreign key from one table pointing to the other table.
See Entity Framework zero-or-one-to-one
class PictureDescription
{
public int Id {get; set;}
public string Title {get; set;}
...
// every PictureDescription has zero or one PicturePrice
public virtual PicturePrice PicturePrice {get; set;}
}
class PicturePrice
{
public int Id {get; set;}
public decimal Price {get; set;}
...
// every PicturePrice belongs to exactly one Picture, using foreign key
public int PictureDescriptionId {get; set;}
public virtual PictureDescription PictureDescription {get; set;}
}
This will be enough for entity framework to detect your columns and the relations between the tables. If you want to use fluent API, in DbContext.OnModelCreating:
// every PictureDescription has zero or one PicturePrice:
modelBuilder.Entity<PictureDescription>()
.HasOptional(description => description.PicturePrice)
.WithRequired(price => price.PictureDescription)
.HasForeignKey(price => price.PictureDescriptionId);
I have been using EF Code First for 1 month. My project needs to work with many tables (over 100 tables of data) and they will be changed many times in the future. It hard to control and take time to add the migration.
So is there any solution to skip the add-migration step, just create the table in the database and create a mapping to the Entity?
Example:
In database I have a table like this:
CREATE TABLE dbo.MyTable
(
Id INT,
Name VARCHAR(255),
Description VARCHAR(1000)
);
I want to map it to the following entity:
public class MyEntity
{
public Id int {get; set;}
public Name string {get; set;}
public Description string {get; set;}
}
My expected solution is something like this:
CreateMap("dbo.MyTable", MyEntity)
Use the attribute System.ComponentModel.DataAnnotations.Schema.Table
[Table("MyTable")]
public class MyEntity
{
public Id int {get; set;}
public Name string {get; set;}
public Description string {get; set;}
}
If you don't actually want to run the migrations, I suggest create them anyway and comment out the relevant code before you run them. That way you will be well set up for the occassion when you do actually want to run them.
You can define the entity maps by overriding the method called OnModelCreating in your DbContext:
Then you can add some maps similar to:
modelBuilder.Entity<Order>(m => {
m.ToTable("MyTable", "dbo");
})
Info: https://learn.microsoft.com/en-us/ef/core/modeling/relational/tables
EDIT: I don't like adding annotation directly to my entity as I prefer to centralize it in one place. Easier to manage. After all I guess it's a question of preferences :)
After switching a project from the EntityObject generator to DbContext, I ran into an issue using some navigation properties on new objects. I've spent a significant amount of time researching the problem, and I'm no closer to a desirable solution.
First, the generated class definitions:
public partial class Category
{
public Category()
{
this.Limits = new HashSet<Limit>();
}
public int CategoryId {get; set;}
public string Name {get; set;}
public virtual ICollection<Limit> Limits { internal get; set; }
}
public partial class Limit
{
public int CategoryId {get; set;}
public string Description {get; set;}
internal virtual Category Category { get; set; }
}
I am creating test data during an integration test using the following code:
using (GFCAMDataContext db = new GFCAMDataContext())
{
limit = new Limit()
{
CategoryId = testData.CategoryId,
Description = "SignerController.Update"
};
db.Limits.Add(limit);
db.SaveChanges();
}
Without any other changes, the Limit.Category property of my newly-created Limit object does not return anything. However, if I query the desired Category from the DbContext before SaveChanges is called the navigation property on my new Limit starts returning the associated Category. With ObjectContext, the Category property is updated without any intervention from me.
I would like to have the same behavior as ObjectContext, but I can't seem to find a way to achieve this goal. I've seen a couple of proposed solutions:
Make the navigation properties public. This had the same behavior, and isn't desirable as the public navigation properties can cause issues during serialization and aren't needed outside of my business layer.
Make all properties public virtual and use DbSet.Create to ensure proxy creation. This resulted in the same behavior, and isn't necessarily desirable as I have code dynamically creating instances (i.e. I don't have access to a DbSet at the time I am creating an entity instance).
Does anyone have any suggestions for a solution to this problem?
One solution would be to explicitly load the nested entity:
db.SaveChanges();
db.Entry(person).Reference(z => z.Category).Load();
The other option, when proxies are enabled, is indeed to call DbSet.Create<T>(). If you don't have access to the DbSet instance at the time you create your entities, you might want to expose a public method in your repository interface that allows that. For example:
public interface IRepository<T>
{
T Add(T entity);
T GetById(...);
void SaveChanges();
...
T CreateInstance(); // Concrete implementation have access to DbSet and uses DbSet.Create<T>()
}
The official approach to defining navigation properties for complex entities is:
public class SuperEntity
{
public int Id { get; set; }
//Other properties
}
public class LowerEntity
{
public int Id { get; set; }
public int SuperEntityId { get; set; }
public virtual SuperEntity SuperEntity { get; set; }
//Other properties
}
The main thing here is that a class that references (allows navigation to linked super entity) has both public SuperEntity SuperEntity { get; set; } property, as well as it's Id in public int SuperEntityId { get; set; }.
I have gone a few days into my entities design ommiting the public int SuperEntityId { get; set; } property in the "lower entities". So I am navigating only by virtual SuperEntity property. And everything works fine! But I had people on SO telling me that it creates an excessive tables in the DB. I've checked, and that is not true. When I use my approach, the DB tables has the SuperEntityId column and just populates it with the referenced entity Id automatically. What's the point in this public int SuperEntityId { get; set; } field then?
Or, perhaps, what I am doing became available in a "fresh" versions of EF like 4.3?
The point of SuperEntityId is that it is sometimes easier to use a foreign key property in apps where your context isn't alive the entire time, e.g. a webapp.
In such a situation, it's a lot easier to just use a foreign key property, than to try to attach object B to object A.
As far as I know, with nav properties, EF uses an object to track the relation between 2 objects. So if you want to couple object B to object A, in a disconnected app, it's not enough to just set the property on object A, you also have to fiddle with the entry of object A in the changetracker to register the relation between B and A.
Setting a foreign key property is the equivalent of this fiddling.
When we were just beginning with EF and didn't know about all of this, every time we wanted to connect 2 objects, e.g. B to A, and B already existed in the DB, the context thought that B was a new object instead of an existing one, and duplicated the record in the DB.
It won't create excessive tables, but it will probably generate extra, or longer, queries on that database. But that depends on how you're using these entities.
The Model as below:
public class User
{
public int Id
public virtual ICollection<Tag> FollowingTags {get;set;}
}
public class Tag
{
public int Id
public virtual ICollection<User> Followers {get;set;}
public virtual ICollection<Post> Posts {get;set;}
}
public class Post {
public int Id
public virtual ICollection<Tag> Tags {get;set;}
}
That means there are two many-to-many from User to Post, perhaps it can be called a M:M:M relationship.
Now, if I want to find all posts with tags that followed by a certain User. I wonder what is the best practice with EF 4.1?
If use ADO.NET, I think joining two joint tables is effective way, but joint tables are hidden in EF, then how to do it ? I know some solutions, but the performance is not good, because the generated SQL not good enough. so I ask for a good query to get good performance.
Thank you!
Try using the "include" modifier in your query like:
context ctx = new context() // context is the entity context in this case
var query = from p in ctx.posts.include("tags.users")
where p.tags.Followers.ID = TargetUserID
This should cover it
(from p in db.Posts
from t in p.Tags
from f in t.Followers
where f.Id == id
select p).Distinct()