EF Core - Reuse Table entity - c#

I have a database, which exists on 3 different stage servers.
The database is identical on all three servers.
I write an application to sync the database tables based on some logic.
For that approach i wrote an generic database context which contains the entites, because they are identical on all servers as well:
public abstract class GenericContext : DbContext
{
public GenericContext(DbContextOptions<ContextA> options)
: base(options)
{
}
public GenericContext(DbContextOptions<ContextB> options)
: base(options)
{
}
public GenericContext(DbContextOptions<ContextC> options)
: base(options)
{
}
public DbSet<Application> Applications { get; set; }
[...]
}
The thought behind this was to handle the entites like Application centralized.
The entity Application looks like:
[Table("Applications", Schema = "dbo")]
public class Application
{
public string Alias { get; set; }
[Key]
public int Id { get; set; }
[...]
}
In my startup class i register all 3 contexts with their matching DbContextOptions.
The reason for the approach is that my repositories expect a genric context to minimize the overhead to handle 3 different database types.
An example of this is:
public int AddApplication(GenericContext context, Application entity)
{
context.Applications.Add(entity);
return entity.Id;
}
When i start my application everything works fine, until i try to access one of the contexts and they get actually build up.
Then the following exception is thrown:
Cannot use table 'dbo.Applications' for entity type 'Application'
since it is being used for entity type 'Application' and potentially other
entity types, but there is no linking relationship.
Add a foreign key to 'Application' on the primary key properties and
pointing to the primary key on another entity type mapped to 'dbo.Applications'.
As the exception states it seems to be not possible to reuse the table entity for multiple contexts.
Is there any way to manage the entities in the desired centralized way but avoid the exception?

Finally i found the source of my error.
The entity Application was used in more than one of my contexts.
My thought was, that they were identically because the point to the same database table, but they differ in some of the navigation properties and so ef core correctyl states that the table is used more then once.
My solution was to unify the entity Application for both contexts.

Related

Entity Framework core navigation property between two contexts

There are similar questions with this issue, but not for EF Core. Not a duplicate of Entity Framework Core Using multiple DbContexts . That one is related to not being able to access the database at all from the second context, and the two contexts use different databases. This question is about a single database and the issue is related to migrations
I have two EF core db contexts using the same SQL Server database.
In the first context I have many entities, one of them is User.
In the second one there is a single entity called UserExt which has a navigational property to User
public class UserExt
{
[Key]
public long UserID { get; set; }
public virtual User User { get; set; }
[Required]
public string Address { get; set; }
}
The issue is that when creating the migration for UserExt using 'add-migration', all entities from the first context are also included.
Tried providing the context, but same result
add-migration --context SecondContext
With EF 6 it was possible to solve this using ContextKey (https://msdn.microsoft.com/en-us/library/system.data.entity.migrations.dbmigrationsconfiguration.contextkey(v=vs.113).aspx) but has not been ported to EF Core
Is there a way to make this work so that the migrations in the second context would contain only its entities ?
Solved using database context inheritance. This way I can have separate migrations.
public class SecondDbContext : FirstDbContext
{
public virtual DbSet<UserExt> ExtendedUsers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("connectionString", options =>
options
.MigrationsAssembly("SecondDbContextAssemblyName")
.MigrationsHistoryTable("__SecondEFMigrationsHistory") // separate table to store migration history to avoid conflicts
);
}
}
Because SecondDbContext is inherited from FirstDbContext, every entity change made in the base context will be inherited. Which means that when a new migration is added to the second context, it will try to apply the changes again from the first context again. Workaround is to:
Add a new migration (for example Add-Migration Inherit_FirstDbContext)
Delete everything from the migration's Up and Down methods
Apply the empty migration in the database. (Update-Database)
This ensures that the Entity Framework snapshot will contain the changes, without actually having to re-apply them in the database.

One-to-One circular reference in EF

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.

allowing a user to define a table at runtime using entity framework

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

MVC 4 and EF6 database first: issue with mapping

I am following along Pro ASP.NET MVC 4 by Adam Freeman on VS 2010 (I downloaded the MVC 4 template online). I have worked with the .edmx file before, but in Chapter 7 he does not do this. I setup a basic connection string with SQL Server in my web.config file within my WebUI project where my controllers and views are located. Also, I listed my Domain classes within my Domain project below. The problem comes when I run the application. The application is not recognizing my table in my database (dbo.Request) and instead is creating a table based on my class name in the Entities namespace (so it creates a CustRequest table) and it also creates a _Migration_History table. To prevent this I add the Data Annotation above my class [Table("MyTableName")]. I could not figure out why I had to add this Data Annotation. Also, EF made me add a [Key] above my primary key, which i can understand because i do not have an ID property, but in the book he did not do this. I was wondering if I was missing something obvious as I am pretty new to MVC. Any help would be appreciated. I am working with EF 6. Thank you.
namespace Requestor.Domain.Entities
{
[Table("Request")]
public class CustRequest
{
[Key]
public int RequestId { get; set; }
public string RequestByUserCd { get; set; }
public DateTime RequestDateTime { get; set; }
public DateTime DueDate { get; set; }
}
}
namespace Requestor.Domain.Abstract
{
public interface ICustRequestRepository
{
IQueryable<CustRequest> Request { get; }
}
}
namespace ITRequestHub.Domain.Concrete
{
public class EFDbContext : DbContext
{
public DbSet<CustRequest> Request { get; set; }
}
}
namespace ITRequestHub.Domain.Concrete
{
public class EFCustRequestRepository : ICustRequestRepository
{
private EFDbContext context = new EFDbContext(); //retrieves the data
public IQueryable<CustRequest> Request
{
get { return context.Request; }
}
}
}
Consider trying again with EF5 if you can, I experienced similar issues when trying to make EF6 work with MVC4 (I couldn' make scaffolding work either).
Or go all the way up to the latest versions for everything and try MVC5 with EF6 (this seems to work fine)
You've run into the wonderful and sometimes frustrating part of EF, its conventions. Wonderful when you're aware of the conventions as they simplify life, but frustrating when you feel that the framework is performing tasks without your explicit permission.
Firstly, additional information on EF6 conventions can be found here: http://msdn.microsoft.com/en-gb/data/jj679962.aspx
On your first point, as far as I'm aware, EF takes the name of your entity as the name of the table it will create in your DB. As you've discovered, you do have control over this via the "Table" attribute, but you can also control it's desire to want to pluralize your entity names when creating tables by means convention removal within your DbContext
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>()
On your second point, I cannot imagine that you would require a "Key" attribute attached to your "RequestId" field. The convention here is that if the field name contains a suffix of ID (case-insensitive), then EF will automatically include it as a primary key and if the type of the field is either an Int or a Guid it will be automatically set as an auto-seed identity column.

EF: Database design issues regarding cross database relations

Summary
I am currently prototyping a (very straight-forward?) multi-tenant web-application where users (stored in database 1) can register to different tenants (stored in a database per tenant (same db schema). An architecture that I thought would apply to a lot of multi tenant solutions.
Sadly, I found out that cross database relations are not supported in Entity Framework (I assumed it's still the case for EF6). I provided the links below.
The next short sections explain my problem, and ultimately my question(s).
The rational behind the design
I choose to have separate databases; one for users (1), and one for each tenant with their customer specific information. That way a user does not have to create a new account when he joins another tenant (one customer can have different domains for different departments).
How it's implemented
I implemented this using two different DbContexts, one for the users, and one for the tenant information. In the TenantContext I define DbSets which holds entities which refer to the User entity (navigation properties).
The 'per-tenant' context:
public class CaseApplicationContext : DbContext, IDbContext
{
public DbSet<CaseType> CaseTypes { get; set; }
public DbSet<Case> Cases { get; set; }
// left out some irrelevant code
}
The Case entity:
[Table("Cases")]
public class Case : IEntity
{
public int Id { get; set; }
public User Owner { get; set; } // <== the navigation property
public string Title { get; set; }
public string Description { get; set; }
public Case()
{
Tasks = new List<Task>();
}
}
The User entity
[Table("Users")]
public class User : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
}
This User entity is also contained by the Users database by my other DbContext derivative:
public class TenantApplicationContext : DbContext, IDbContext
{
public DbSet<Tenant> Tenants { get; set; }
public DbSet<User> Users { get; set; } // <== here it is again
// left out irrelevant code
}
Now, what goes wrong?
Expected:
What I (in all my stupidity) thought that would happen is that I would actually create a cross database relation:
The 'per-tenant' database contains a table 'Cases'. This table contains rows with a 'UserID'. The 'UserID' refers to the 'Users' database.
Actual:
When I start adding Cases I am also creating another table 'Users' in my 'per-tenant' database. In my 'cases' table the UserID refers to the table in the same database.
Cross database relations do not exist in EF
So I started googling, and found that this feature simply is not supported. This made me think, should I even use EF for an application like this? Should I move towards NHibernate instead?
But I also can't imagine that the huge market for multi tenant applications simply is ignored by Microsoft's Entity Framework?! So I most probably am doing something rather stupid.
Finally, the question...
I think the main question is about my 'database design'. Since I am new to EF and learning as I go, I might have taken the wrong turn on several occasions (is my design broken?). Since SO is well represented with EF experts I am very eager to learn which alternatives I could use to achieve the same thing (multi tenant, shared users, deployable in azure). Should I use one single DbContext and still be able to deploy a multi tenant web-application with a shared Users database?
I'd really appreciate your help!
Things learned:
NHibernate does support cross database relations (but I want to deploy into Azure and rather stick to microsoft technologies)
Views or Synomyms can be an alternative (not sure if that will cause more difficulties in Azure)
Cross database relations are not supported by EF:
EF4 cross database relationships
ADO.Net Entity Framework across multiple databases
Entity framework 4 and multiple database
(msdn forum with EF devs) http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/cad06147-2168-4c20-ac23-98f32987b126
PS: I realize this is a lengthy question. Feel free to edit the question and remove irrelevant parts to improve the readability.
PPS: I can share more code if needed
Thank you so much in advance. I will gladly reward you with upvotes for all your efforts!
I don't quite understand why do you need cross database relations at all. Assuming your application can talk to the two databases, the user database and a tenant database, it can easily use the first database for authentication and then find related user in the tenant database with "by name" convention.
For example, if you authenticate a user JOHN using user database then you search for a user JOHN in the tenant database.
This would be much easier to implement and still match your requirements, users are stored in users database together with their passwords and "shadow copies" of user records but with no passwords are stored in tenant databases and there is NO physical relation between these two.

Categories