I have a common database that multiple applications use, and one of the tables in that common database is a Person table.
I know I can't have foreign key relationships cross database.
However, I was hoping I could still do something like
public Programmer
{
public virtual Common.Models.Person Person { get; set; }
}
(Programmer is a table in a different database than the person table)
Now, that wants to create a foreign key to a different database, which it can't, so it wants to recreate the tables in the database with the Programmer table.
I don't want that to happen, I just want to be able to do Programmer.Person and it grab the person model from the common database.
Since you can't use FKs which is what makes this possible, is there a way around this? Or what is the best practice to deal with a common database like this?
Thank you.
Related
I have a specific EF Core 6.x question.
If the SQL table has a column removed. Then EF Core will throw a SqlException saying that it's an invalid column name unless I also update the C# model.
For example,
Create Table User
(
FirstName varchar(200)
,MiddleName varchar(200) null -- tried to remove this column after table is created
,LastName varchar(200)
)
I tried deleting the MiddleName column from the SQL Table. When I run a simple read call using EF Core 6, I get the error.
c# model
public class User
{
public virtual string FirstName { get; set; }
public virtual string? MiddleName { get; set; }
public virtual string LastName { get; set; }
}
var db = new EFDbContext(connectionString);
var data = db.Users.ToList(); // SqlException here after column removal
Is there any way to remove columns from the table without needing to update the c# class as well?
Tried making the C# property MiddleName not virtual.
Update:
In the event that I have an existing application. I would need to modify the c# model even if the codebase doesn't refer to the removed column anywhere. Alternatively, I can decorate the property with [NotMapped] or use the Ignore() method in the modelbuilder.
Both approaches means a rebuild of the assembly is needed and downtime during deployment.
NHibernate's mapping can be done using an XML file and thus all it takes would be a simple config file update.
I can't seem to find anything in EF Core that will reduce the headache of maintaining older codebases when schema changes occur.
EF creates a data model mapping internally to track the database schema and your code models. By removing the column in your database table, your code model no longer matches the database. Hence, the exception occurs.
This is definitely not be the answer you're looking for, but as far as I know EF Core need consistency between the models and the DB schemas to work.
I can think of 2 things here:
Maybe you could benefit from using a different ORM (Did you give Dapper a cahnce)
You might be facing an architectural issue, if there's more than one team working with the same database, and more than one system calling that database, the best way to avoid headaches in the future would be to isolate the data access layer and expose an API that serves all the involved systems.
That way, if the database changes, you just need to re-build the data access layer, no downtime for your clients.
And finally... in my opinion the ideal solution is a combination of both, create a decoupled data access layer, map things there and expose an API with the models your application needs.
I am currently modeling two classes in asp.net using entity framework 6 using a code-first approach. A user can create a Widget, where a Widget has a collection of up to five WidgetOptions. The options are primarily strings but there is metadata associated with them that other users need to interact with (hence why they are not just a collection of strings). Currently, my classes look something like this:
Widget {
public string Name {g;s;}
... //more fields
public string ICollection<WidgetOption> Options {g;s;}
}
WidgetOption {
public string Option {g;s;}
... //more fields
}
This obviously seems simple enough, but here are my thoughts. So currently, when a user creates a widget in the UI, the controller is creating a list of WidgetOptions from the strings that the user enters, assigning the WidgetOptions to the Widget, then saving to the database context. As in:
Create(WidgetFormViewModel vm) {
var options = vm.WidgetOptions.Select(wo => new WidgetOption(wo)).ToList();
var widget= new Widget {
Options = options,
// ... other fields from vm
};
_context.Widgets.Add(widget);
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
The problem is that many users are likely to repeat WidgetOption strings. For instance, a lot of users might name an option "red" to make the Widget red (while that may seem weird, the actual case makes a lot more sense). Entity Framework is currently modeling the classes as having no columns in Widget that reference WidgetOption, and the WidgetOption having Id, Option, and Widget_Id columns.
So if two users make a Widget with a "red" WidgetOption, there will be two rows created in the WidgetOption table. Each with a unique Id and each with the corresponding Widget_Id. This seems really inefficient in terms of space, but I could be wrong (in that it's not as much space as I think is being wasted). I guess, even if I had a separate table with only unique WidgetOption strings, I would still need a relationship table that connected a Widget to Many WidgetOptions. That could be more efficient than the current model if the WidgetOption_Id in the relationship table was much smaller than the string itself, right? Except then I would have to search for each string that the user enters to see if it had been created. So I'd be sacrificing speed for storage.
I'm not sure if I'm overthinking this or not, but I just feel weird having a table where WidgetOptions are repeated. If there were only a few unique option strings, a many to many relationship makes more sense, while the current model would make sense if every option string was unique. It seems like the right choice can only be solved by figuring out which end of this scale occurs in practice.
Rewrite your Widget and WidgetOption entities this way:
Widget {
public string Name {g;s;}
... //more fields
public virtual ICollection<WidgetOption> WidgetOptions {g;s;}
}
WidgetOption {
public string Option {g;s;}
... //more fields
public virtual ICollection<Widget> Widgets {g;s;}
}
It would tell Entity Framework to define many-to-many relationship between Widget and WidgetOption. I believe this should take care of the issue that has been bothering you. Though, it might require a little change in code to add WidgetOptions.
I am currently working towards implementing a charting library with a database that contains a large amount of data. For the table I am using, the raw data is spread out across 148 columns of data, with over 1000 rows. As I have only created models for tables that contain a few columns, I am unsure how to go about implementing a model for this particular table. My usual method of creating a model and using the Entity Framework to connect it to a database doesn't seem practical, as implementing 148 properties for each column does not seem like an efficient method.
My questions are:
What would be a good method to implement this table into an MVC project so that there are read actions that allow one to pull the data from the table?
How would one structure a model so that one could read 148 columns of data from it without having to declare 148 properties?
Is the Entity Framework an efficient way of achieving this goal?
Entity Framework Database First sounds like the perfect solution for your problem.
Data first models mean how they sound; the data exists before the code does. Entity Framework will create the models as partial classes for you based on the table you direct it to.
Additionally, exceptions won't be thrown if the table changes (as long as nothing is accessing a field that doesn't exist), which can be extremely beneficial in a lot of cases. Migrations are not necessary. Instead, all you have to do is right click on the generated model and click "Update Model from Database" and it works like magic. The whole process can be significantly faster than Code First.
Here is another tutorial to help you.
yes with Database First you can create the entites so fast, also remember that is a good practice return onlye the fiedls that you really need, so, your entity has 148 columns, but your app needs only 10 fields, so convert the original entity to a model or viewmodel and use it!
One excelent tool that cal help you is AutoMapper
Regards,
Wow, that's a lot of columns!
Given your circumstances a few thoughts come to mind:
1: If your problem is the leg work of creating that many properties you could look at Entity Framework Power Tools. EF Tools is able to reverse engineer a database and create the necessary models/entity relation mappings for you, saving you a lot of the grunt work.
To save you pulling all of that data out in one go you can then use projections like so:
var result = DbContext.ChartingData.Select(x => new PartialDto {
Property1 = x.Column1,
Property50 = x.Column50,
Property109 = x.Column109
});
A tool like AutoMapper will allow you to do this with ease via simply configurable mapping profiles:
var result = DbContext.ChartingData.Project().To<PartialDto>().ToList();
2: If you have concerns with the performance of manipulating such large entities through Entity Framework then you could also look at using something like Dapper (which will happily work alongside Entity Framework).
This would save you the hassle of modelling the entities for the larger tables but allow you to easily query/update specific columns:
public class ModelledDataColumns
{
public string Property1 { get; set; }
public string Property50 { get; set; }
public string Property109 { get; set; }
}
const string sqlCommand = "SELECT Property1, Property50, Property109 FROM YourTable WHERE Id = #Id";
IEnumerable<ModelledDataColumns> collection = connection.Query<ModelledDataColumns>(sqlCommand", new { Id = 5 }).ToList();
Ultimately if you're keen to go the Entity Framework route then as far as I'm aware there's no way to pull that data from the database without having to create all of the properties one way or another.
I was hoping someone could give me a bit of advice here. I am wondering if I am on track or way off base in my approach. I am using Entity Framework, database first approach. I have a link table that associates people to each other. Person 1 associated to Person 2 as a friend for example. (association_type holds a key value associated to a lookup table)
I noticed that Entity Framework creates two separate navigation properties.
[EdmRelationshipNavigationPropertyAttribute("IntelDBModel", "FK_a_Person_Person_t_Person", "a_Person_Person")]
public EntityCollection<a_Person_Person> a_Person_Person
[EdmRelationshipNavigationPropertyAttribute("IntelDBModel", "FK_a_Person_Person_t_Person1", "a_Person_Person")]
public EntityCollection<a_Person_Person> a_Person_Person1
In other parts of the application, I have successfully used Entity Framework to write data to the database. For example, I have a person to telephone relationship.
In the person to telephone scenario, I create a t_Person (p) object, then create a t_Telephone (t) object and use p.t_Telephone.Add(t);
That seems to work fine.
I am somewhat lost in terms of how to manage this person to person link table insert.
When saving to the database, I use foreach to iterate through the People objects.
foreach (t_Person p in People)
{ctx.t_Person.AddObject(p);
...
}
I know what person is associated to what person in this People object collection. However, I don't know how to utilize the t_Person navigation properties (a_Person_Person) to save the person1 and person2 values to the link table (a_Person_Person).
Any hints would be greatly appreciated.
I think the given situation will generally give you hard time when using EF, since you are linking two foreign key two one table with same Primary key, since the relationship or lazy loading would be difficult to handle you might get double records or wrong records, I would add another property to the t_person table like datecreated which would make the the EF treat t_person table as not an association, but as actual entity giving you more control over entity and insertion and deletion.
The product I'm working on will need to support different database types. At first, it needs to support SQL Server and Oracle, but in the future it may need to support IBM DB2 and Postgre SQL.
And the product will need to be working for different customers who might have slightly different schemas. For example a column name on one client with SQL Server might be _ID and on another client with Oracle it could be I_ID.
The general schema will be the same except the column names. They all could potentially be mapped to the same object. But, there may be some extra columns that are specific to each customer. These do not need to be mapped to an object though. They can be retrieved in a Master-Detail scenario using a simpler way.
I wanted use an ORM as we will need to support different types of database providers. But as far as I can understand, ORMs are not good with creating a mapping on runtime.
To support these requests (summary):
Column names may be different for each customer, but they are pretty much the same columns except names.
Database provider may be different for each customer.
There may be extra columns for each customer.
Edit: Program should be able to support a new database by changing the configuration during runtime.
What is a good way to create a data access for such specifications? Is there a way to do it with ORMs? Or do I need to write code specific to each database to support this scenario? Do I have any other option that would make it easier than using ADO.NET directly?
Edit: I think I wrote my question a bit too broad, and didn't explain it clearly, sorry about that. The problem is I won't be creating the databases. They will be created already, and the program should be able to work with a new database by configuring the program during runtime. I have no control over the databases.
The other thing is, of course it is possible to do it by creating SQL statements in the program, but that is really cumbersome. All these providers have slightly different rules and different SQL implementations, so it is a lot of work. I was wondering if I could use something like an ORM to make it easier for me.
Edit 2: I am totally aware that this is a stupid way to do things, and it shows bad design decisions. But I have spent so many hours trying to convince my company to not do it this way. They don't want to change their way of thinking because an intern tells them so. So any help would be appreciated.
Column names may be different for each customer, but they pretty much the same columns except names.
Because of this requirement alone you're going to have to build your SQL statement dynamically, on your own, but it's really pretty straight forward. I would recommend building a table like this:
CREATE TABLE DataTable (
ID INT PRIMARY KEY NOT NULL,
Name SYSNAME NOT NULL
)
to store all of the tables in the database. Then build one like this:
CREATE TABLE DataTableField (
ID INT PRIMARY KEY NOT NULL,
DataTableID INT NOT NULL,
Name SYSNAME NOT NULL
)
to store the base names for the fields. You'll just have to pick a schema and call it the baseline. That's what goes in those two tables. Then you have a table like this:
CREATE TABLE Customer (
ID INT PRIMARY KEY NOT NULL,
Name VARCHAR(256) NOT NULL
)
to store all the unique customers you have using the product, and then finally a table like this:
CREATE TABLE CustomerDataTableField (
ID INT PRIMARY KEY NOT NULL,
CustomerID INT NOT NULL,
DataTableFieldID INT NOT NULL,
Name SYSNAME,
IsCustom BIT
)
to store the different field names for each customer. We'll discuss the IsCustom in a minute.
Now you can leverage these tables to build your SQL statements dynamically. In C#, you might cache all this data up front when the application first loads and then use those data structures to build the SQL statements. But get started on that and if you have specific questions about that then create a new question, add the code you already have, and let us know where you're having trouble.
Database provider may be different for each customer.
Here you're going to need to use something like Dapper because it works with POCO classes (like what you'll be building) and it also simply extends the IDbConnection interface so it doesn't matter what concrete class you use (e.g. SqlConnection or OracleConnection), it works the same.
There may be extra columns for each customer.
This is actually quite straight forward. Leverage the IsCustom field in the CustomerDataTableField table to add those fields to your dynamically built SQL statements. That solves the database side. Now, to solve the class side, I'm going to recommend you leverage partial classes. So consider a class like this:
public partial class MyTable
{
public int ID { get; set; }
public string Field1 { get; set; }
}
and that represents the baseline schema. Now, everything maps into those fields except those marked IsCustom, so we need to do something about those. Well, let's build an extension to this class:
public partial class MyTable
{
public string Field2 { get; set; }
}
and so now when you build a new MyTable() it will always have these additional fields. But, you don't want that for every customer do you? Well, that's why we use partial classes, you define these partial classes in external assemblies that only get installed for the right customer. Now you have a bunch of small, customer specific extensions to the system, and they are easily developed, installed, and maintained.