I have a class (simplified) in code-first EF6.
public class Transaction
{
public int Id { get; set; }
public int? TransferCounterPartId { get; set; }
public Transaction TransferCounterPart { get; set; }
public bool IsTransfer{get{return TransferCounterPart != null;}}
}
I would characterize this as a circular self reference. I have not added any fluent API, but have tried different scenario's to solve my issue.
My issue is on deleting these entities, or as it will, the couple that makes up a transfer-transaction.
My delete statement:
Manager.Context.Transactions.Remove(transaction.TransferCounterpart);
Manager.Context.Transactions.Remove(transaction);
The Exception:
Unable to determine a valid ordering for dependent operations.
Dependencies may exist due to foreign key constraints, model
requirements, or store-generated values.
If I set the references to eachother to null, SaveChanges, and then remove the entities and SaveChanges again, it goes without a hitch, but this has performance and design implications.
Questions:
How can I delete these two entities?
Solution Directions I can image:
Model differently? (boundary condition, I must easily find the
counterpart when I delete one transaction)
Context Settings or SaveChanges options EF?
Stored Procedures, or execute sql code ?
Fluent API?
Any help will be welcome
psuedo-code modelbuilder.Entity.HasOptional.HasRequired.WillCascasde(true/false) scenario's did not work.
Related
I have a question regarding the setup of foreign keys in entity framework 6. Our project stores data from a few other services (to have faster access to the data) and provides the users with charts and statistics depending on the stored data. For the storage of the data we´ve setup a cronjob which runs daily at about 3 AM.
Here are 2 example database models:
public class Project {
public string Id { get; set; }
public string Title { get; set; }
}
public class Issue {
public string Id { get; set; }
public string Title { get; set; }
[ForeignKey("Project")]
public string ProjectId { get; set; }
[ForeignKey("ProjectId")]
public Project Project { get; set; }
}
The problem now is for some issues we don´t save the project it depends on but we have to save the ProjectId (because at a later point it might be possible that the project exists in our database). So when I try to save this issues it tells me that I can´t save them because the project does not exist.
Is there any way I can tell entity framework that it doesn´t matter if the project exists or not? Currently I´ve just removed the ForeignKeys but this makes it very slow when I try to get the full list of issues with their projects.
Or is there any other way to read out all issues with their projects if there are no foreign keys? Currently I´m using a foreach loop to go threw each issue and then I search for the project but with more than 10.000 issues this get´s very slow.
The navigation property you've defined is requiring the data in the Project table in order to save an Issue. This isn't Entity Framework, this is a SQL Server foreign key constraint issue. Entity Framework is doing preliminary validation to not waste a connection that will ultimately fail. While you can turn off enforcing the foreign key constraint, there is not a good way to turn this validation off in Entity Framework
Keep in mind, having a foreign key does not mean it will help with your query's performance. It's simply a way to enforce referential integrity. I suspect that your real problem is the way you've written your query. Without seeing your query and metrics around "slow", it be hard to point you in the right direction.
is it possible to dynamically build entities in entity framework 6 using code first?
is it also possible to add properties to those entities at runtime?
Can those entities reference each other using foreign keys?
If someone could point me in the right direction if this is possible, i would really appreicate it.
EDIT
i have changed the title to reflect more of what i would like, so u can see why i asked the questions i asked.
Basically i would like to create a system where a user can define the objects(tables) they want, with the properties on that object (columns in table) as well as the references to each object (relationships between tables).
Now each object would have an Id property/column. i was thinking of atoring these definitions in an eav like table structure but i have other ibjects that are defined at design time and i like to use linq queries on these objects. I would also like to be able to build linq queries on these objects as users will want to report on this data. Building the linq queries should be fine as could use dynamic linq for this (Maybe)?
Currently to create such a system i have created a table that has many text fields, many number fields, many relationship fields and users can use which ones they want. But this is just 1 table and i think this is going to bite me in the bottom in the end, thus why i would like to take it to the next level and build separate tables for each object.
if anyone knows of a better way or maybe experienced something similar, glad to hear opinions.
Ive been interested in this topic since ef4.
Have a real world solution that could use it.
I dont...
Rowan Miller is one of the EF developers. He wrote a blog on this topic.
Dynamic Model creation Blog Explaining how you might do it.
A github example buybackoff/Ractor.CLR see OnCreating Showing how.
It would appear ok, but has a many practical restrictions that make
a recompile with generated code or hand code more practical.
It is also why i have not down voted others. :-)
Would it be fun watching someone dig their own grave with a teaspoon?
Consider the runtime implications.
These approach still rely on the POCO type discovery.
the an assembly can be generated from code on the fly.
And then there is SO POCO and runtime
During context creation the initializer runs. You adjust the model.
The auto migrate then adds the news properties and tables.
So during that period of time NO other contexts can be instantiated.
Only non EF access possible during the automatic migration.
So you still have a logical outage.
You are now using previously unknown pocos, in unknown tables.
What repository pattern are you using...
eg I used this type of pattern....
private IRepositoryBase<TPoco> InstantiateRepository(BaseDbContext context, Type repType, params Type[] args) {
Type repGenericType = repType.MakeGenericType(args);
object repInstance = Activator.CreateInstance(repGenericType, context);
return (IRepositoryBase<TPoco>)repInstance;
}
and cast this against IRepository after making a dynamic call to the factory.
But i was unable to avoid dynamic calls. Sticky situation.
good luck....
Edit / After thought
I read a blog about ef 7
There are some very interesting comments from Rowan about potentially not needing CLR types. That makes the dynamic game a bunch easier.
You could try the ef7 beta if brave.
You can create an EF model dynamically using reflection:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
foreach (Type type in ...)
{
entityMethod.MakeGenericMethod(type)
.Invoke(modelBuilder, new object[] { });
}
base.OnModelCreating(modelBuilder);
}
it possible to dynamically build entities
The short answer is no, one cannot dynamically build new or existing entities once EF has defined them during design time.
is it also possible to add properties to those entities at runtime
But that does not mean one has to live with those entities as they are... To achieve a dynamism one can extend the entities via Partial class to the entity. Then one can have any number of new properties/methods which could achieve what the runtime aspect which possibly you are looking for past a generated entity.
Can those entities reference each other using foreign keys?
Not really, but it is not clear what you mean.
If the entity was generated in design time and during runtime a new FK constraint was added to the database, then an entity could be saved if it does not know about the FK, but if the FK requires a value then the process of saving would fail. Extraction from the database would not fail.
Q: is it possible to dynamically build entities in
entity framework 6 using code first?
A: No
Q: is it also possible to add properties to those entities at runtime?
A:No
Q: Can those entities reference each other using foreign keys?
A: Unless you've defined the entity beforehand, no.
Maybe you've confused things with what's called CodeFirst, where you write your domain / business models in C#, define their relationships with other entities, and then generate a database based on your C# models...
Here's an overly simplistic example that you can get started with if that's what you're trying to achieve.
First make sure you have EntitiyFramework installed... you can get it from NuGet...
pm> Install-Package EntityFramework
Then copy the code below to your project
public class User
{
public User()
{
this.Id = Guid.NewGuid().ToString();
}
public string Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts {get;set;}
}
public class Post
{
public Post()
{
this.Id = Guid.NewGuid().ToString();
}
public string Id { get; set; }
public string UserId { get; set; }
public virtual User Author {get;set;}
public string Title { get; set; }
public string Body { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
this.ToTable("Users");
this.HasKey(user => user.Id);
this.Property(user => user.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(user => user.Name).IsRequired();
this.HasMany(user => user.Posts).WithRequired(post => post.Author).HasForeignKey(post => post.UserId);
}
}
public class PostConfiguration : EntityTypeConfiguration<Post>
{
public PostConfiguration()
{
this.ToTable("Posts");
this.HasKey(post => post.Id);
this.Property(post => post.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(post => post.UserId).IsRequired();
this.Property(post => post.Title).IsRequired();
this.Property(post => post.Body).IsRequired();
this.HasRequired(post => post.Author).WithMany(user => user.Posts).HasForeignKey(post => post.UserId);
}
}
public class ExampleContext : DbContext
{
public ExampleContext() : base("DefaultConnection")
// Ensure you have a connection string in App.config / Web.Config
// named DefaultConnection with a connection string
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new PostConfiguration());
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
Once you've done that... Open the package manager console and type in the following commands...
pm> Enable-Migrations
pm> Add-Migration InitialMigration
pm> Update-Database
And you should then have your database generated for you from that
I'm trying to implement an Undo / Redo feature based on entity framework with POCO entities. Therefor after each change that I want to track I call the ChangeTracker for any modification to entities an I call the ObjectStateManger for changes to relationships (i.e. navigation properties). I store all the changes with the current and previous values to be able to go back and forth in the history.
My problem now is that for entities with a navigation property and a corresponding foreign key these two values are not properly synced if the referenced entity was newly added to the DbContext.
To clarify: Say I have these classes:
public class EntityFilter
{
[Key]
public Guid ID { get; set; }
public virtual ICollection<EntityConnection> IsSource { get; set; }
public virtual ICollection<EntityConnection> IsSink { get; set; }
//other stuff
}
public class EntityConnection
{
[Key]
public Guid SinkFilterID { get; set; }
[ForeignKey("SinkFilterID")]
public virtual EntityFilter Sink { get; set; }
public Guid SourceFilterID { get; set; }
[ForeignKey("SourceFilterID")]
public virtual EntityFilter Source { get; set; }
//more stuff
}
EntityConnection is basically a many-to-many relationship between filters, but it actually contains more fields which is why I cannot get rid of it. Also I want to be as general as possible and not depend on our actual data model.
The problem arises if I add a new filter and then connect it to an existing filter (could also be a new one). Undoing the connection is still ok, but when I try to redo my program will crash. I can see in the restored connection that the foreign key SinkFilterID has the correct value but Sink is null (the same might happen for source, depending on the direction of the connection). Manually calling DetectChanges makes no difference. Adding a connection between two existing filters (i.e. they are already stored in the db before) is no problem.
The detected changes for a new connection of this type only contain entity changes from the ChangeTracker and no relationship changes from the ObjectStateManger. I guess this is because the relationship is already handled by the foreign key, which is included in the properties from PreviousValues.
I've read that entities in the EntityState.Added state get temporary keys and that change tracking for them is not fully supported. Can I get this to work somehow?
I've tried to check with the MetadataWorkspace if my updated entities have a foreign key and a corresponding navigation property and in that case update it manually via reflection, but I'm not sure what data I actually have to check.
Is there a way to keep foreign keys and navigation properties to added entities in sync? Or do you have any suggestions what I might try?
Thank you very much.
Here is what I ended up with:
I keep a separate list of all the added entities. Then when I have to restore a navigation property that is backed by a foreign key I search that list and manually set the navigation property. The hardest part was to figure out how to check in the data model if this fixup was at all needed and to find the name of the corresponding property.
The overall system still has some flaws for maximum generality but it works quite well for what we need.
I am using c# with Fluent NHibernate and auto mapping.
Here is some code (truncated for clarity), then I'll explain the problem.
public class Company
{
public virtual string Description { get; set; }
}
public class Stock
{
public virtual Product Product { get; set; }
public virtual Company Company { get; set; }
}
Mapping
mappings.Conventions.Add<CascadeConvention>()
.Conventions.Add<CustomForeignKeyConvention>()
.Conventions.Add<HasManyConvention>()
.Conventions.Add<VersionConvention>()
CascadeConvention just sets everything to All.
CustomForeignKeyConvention removes the _id that NHibernate usually
appends to foreign key id columns.
HasManyConvention sets all HasMany's to inverse.
VersionConvention convertion looks like this:
instance.Column("Version");
instance.Default(1);
The problem is that when I insert a new stock record, Nhibernate also updates the version number on the related Company.
If I had an IList<Stock> property on the Company then that would make sense but I don't.
I've done a lot of reading around:
NHibernate emitting extraneous update statements regardless of proper Inverse (fluent nhibernate) settings on relations
Cascade Save-Update in NHibernate and version column
NHibernate Reference - Chapter 17. Example: Parent/Child
Ayende # Rahien - NHibernate Mapping
From these, I've tried a whole bunch of things including adding .Not.OptimisticLock() all over the place. I even added an IList<Stock> property on Company so that I could specifically set it as Inverse, Not.OptimisticLock, etc. Nothing I do seems to make any difference.
We eventually sorted this by moving to a Session-per-request paradigm. Not sure why it was going wrong or why this fixed it. I wrote numerous unit tests to try and reproduce the behaviour in a more controlled environment without success.
In any case, it works now. There are good reasons session-per-request is often given as the best practice way to manage NHibernate sessions in a web application.
We are trying to get Entity framework working at our shop with an existing database (and therefore, changing the database schema is NOT an option), and the unit tests we created to test things are showing some really strange behavior.
This is the SQL it spits out for a specific object we have:
SELECT
[Extent1].[CommentTypeId] AS [CommentTypeId],
[Extent1].[DataPartId] AS [DataPartId],
[Extent1].[CommentId] AS [CommentId],
[Extent1].[CreatedTime] AS [CreatedTime],
[Extent1].[Message] AS [Message],
[Extent1].[From] AS [From],
[Extent1].[Likes] AS [Likes],
[Extent1].[SourceTypeId] AS [SourceTypeId],
[Extent1].[StatusMessage_DataPartId] AS [StatusMessage_DataPartId],
[Extent1].[Album_DataPartId] AS [Album_DataPartId]
FROM [dbo].[Comments] AS [Extent1]
The last two columns requested, as you might notice, are not like the others. That's because they don't actually exist, and we have no idea why Entity is requesting them! Neither our configuration files nor our POCOs make any mention of them at all. In fact, as far as our database goes, they're completely separate concepts and aren't directly related at all.
Where is it getting these columns from, and how do I tell it to cut it out?
EDIT: To respond to some of the questions below,
1) We are using Entity Framework 4.2. We are using fluent mapping.
2) The POCO itself looks like this, with the equality mess cut out for the sake of brevity:
public long DataPartId { get; set; }
public string CommentId { get; set; }
public DateTime? CreatedTime { get; set; }
public string Message { get; set; }
public string From { get; set; }
public int? Likes { get; set; }
public string SourceTypeId { get; set; }
public int CommentTypeId { get; set; }
public virtual DataPart DataPart { get; set; }
public virtual CommentType CommentType { get; set; }
3) We are not using edmx. We have a custom DbContext. There are not too many lines that are terribly interesting. These two are probably of interest:
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = true;
Beyond that, the Context file is a lot of
modelBuilder.Configurations.Add(new WhateverConfiguration())
and
public IDbSet<WhateverPoco> PocoDatabaseTableAccessor { get; set; }
4) We started with db-first, but that didn't work, so we're currently doing code-first.
5) This is the guts of the config for that specific POCO:
HasRequired (x => x.DataPart)
.WithRequiredDependent (x => x.Comment);
HasRequired (x => x.CommentType)
.WithMany (x => x.Comments)
.HasForeignKey (x => x.CommentTypeId);
HasKey (x => x.DataPartId);
ToTable ("Comments", "dbo");
The problem is not in the mapping or class you showed. Check your Album and StatusMessage classes. Are they entities? Are they mapped? Do they have collection navigation properties to comments? If yes EF expects that Comment must have FK to these tables. If the table doesn't have such column you cannot have these navigation properties mapped in those entities.
Btw. Shouldn't the id in Comments table be CommentId instead of DataPartId?
Entity Framework, like MVC, uses a lot of convention over configuration. That means it assumes certain things unless you tell it not to.
However, something is really strange here based on the information you supplied. According to the SQL query, this is coming from the Comments table, however your fluent mapping says that DataPartId is the primary key. Do you have additional primary key fluent mappings? If not, your mappings may be wrong. Have you checked the actual database generated to see if the data model matches what you are trying to do?
My guess is that your StatusMessage and Album classes have navigational properties to Comment, but since you have only defined DataPartId as your primary key, that is the value it is using to look up the comments, not CommentId.
Open the .edmx in a XML-Editor and search for these columns. They must be somewhere in your model.
EDIT: your original question didn't mention that you are using code first. I wonder what your trouble was with Database first, that usually works fine well. With code first or model first, you normally create the database after creating the model (using generated SQL scripts).
You declared the last two properties as virtual, that's why the generated SQL looks different. From the code you are showing us we cannot see where the reference to Album comes from.
Because you have the database, I would generate the .edmx from the model in one project. Then you can use a POCO code generator or a Self-tracking entity generator to generate the entities and store them in a different project. Or you can write them manually as you already have. The property names must correspond with the columns in the database.