So i like MVC and EF6 but I keep coming across fundamental problems with the way it / I work.
I have an app ( a very simple one) in there one of my tables references a field in another database, how would EF handle this , it seems to get very complicated whereas in the past it would have been a simple ADO.NET call to a stored procedure or something ( I am aware I can use SP's with EF, but really, what's the point , may as well just use ADO.NET again), example model below:
[Table("Target")]
public partial class Target
{
public int ID { get; set; }
public int SomeForeignKeyInMyDbID { get; set; }
public Guid? FOREGINKEYINANOTHERDB { get; set; }
}
when I scaffold views based of this it automatically creates the drop down menus etc really well but it (obviously) cannot pickup the reference to the foreign key in another field, as I want to store the ID of the foreign key in the database but get the value of it for drop downs etc, I store the ID instead of the value for reporting reasons.
I thought that I would just be able to get a context to my other db, grab the values I need and bind them to the drop down list but the model structure is so tightly defined that I face hurdle after hurdle on this.
I read somewhere that my best option may be to use SP's for CRUD operations and then perform a LINQ to EF query fro the index view and do a join on foreginkeyfromanotherdb field.
Any help much appreciated.
Thanks
Related
For my API I'm using Entity Framework Core with code first migrations. I've created some relations which are working fine. Now, I've added another relation (one to many) and suddenly I'm slapped around the ears with this error:
Cannot insert explicit value for identity column in table 'Companies' when IDENTITY_INSERT is set to OFF."
Offcourse, I must be doing something wrong but I just can't figure out what. I've come across more questions like this where the answer was "set IDENTITY_INSERT to ON" but that doesn't work for me since EF is handling everything.
My Company class which can belong to a Group:
public class Company
{
// Primary key
public int Id { get; set; }
// The optional Id of a Group
public int? GroupID { get; set; }
...
}
And the Group class:
public class Group
{
// Primary key
public int Id { get; set; }
// Name of the Group
public string Name { get; set; }
// List of Companies in this group
public IEnumerable<Company> Companies { get; set; }
}
The code used for handling the POST:
// POST api/groups
[HttpPost]
public async Task<IActionResult> Post([FromBody] Group group)
{
try
{
if (ModelState.IsValid)
{
_context.Groups.Add(group);
await _context.SaveChangesAsync();
return CreatedAtRoute("GetGroup", new { id = group.Id }, group);
}
return BadRequest(ModelState);
}
catch (Exception e)
{
return BadRequest($"Unable to create: {e.Message}");
}
}
In my database, all columns, index and keys are created as expected and just like every other one to many relationship I've got in my API. But this specific case just seems to end up in misery...
The class I'm trying to add to the database:
Problem is that there's no hint for EF to know if Company (under Group relationship) is being explicitly inserted or if it is supposed to use the pre-existing one from database.
Since those instanced are disconnected from DbContext there is no indication whether they exist or not on the database by the time EF tries to generate its SQL command.
There is no easy way here, at least there was none by the time I've played with EF Core.
You should either:
Change your code to only use the ID instead of the navigation property so you'll avoid this whenever possible, or;
Change your code to fetch related data (eg: fetch Company and attach it to Group) before saving desired data (eg: before saving Group).
So, for instance:
var companyDB = await context.Companies.SingleOrDefaultAsync(c => c.Id == group.Company.Id);
group.Company = companyDB;
context.Groups.Add(group);
await context.SaveChangesAsync();
Yes, you're making two trips to database. That's why I'd suggest using the first approach, so you can avoid this fetch and just save Group entity directly into DB.
That does not, however, prohibits you from sending a navigation instace of Company to your view. Just create some entity-related classes which will correlate to your database so you can load/save data using this entity type, and create a Dto object which will be your endpoint input/output whenever needed.
Binding one into another can be done by using AutoMapper, manual linq or other approaches.
This is because you are passing some value in a column which is set as identity (auto-increment).
I think the Group entity which you are inserting has the companies with the value of Id which it tries to insert in company table as child record. and it throws an error.
I had a similar problem when trying to save an entity (for ex., Cat) which had many-to-one relationships to existing entities (property Owner, pointing at Person). In addition to a) getting the relationship (Person) from the database before saving the entity (Cat), and b) adding another property (int PersonId) to the entity (Cat), I discovered what I think is the best solution: c) stick to "navigation" properties only (do not create extra int <<Name>>Id properties), and when referencing is needed, use cat.Owner = dbContext.Person.Attach(new Person { Id = 123 }).Entity;
Entity Framework lost tracking for some reason and Entity Framework needs to reestablish tracking for the entities that are already existing.
You can get the state of the entity's tracking with:
var entityTrackingState = _context.Entry(entity).State;
You can force Entity Framework to do tracking on the existing entities with:
_context.Entry(untrackedEntity).State = EntityState.Unchanged;
Where
_context
is an Entity Framework DbContext.
Forcing tracking resolved my issue, but it really should be debugged where Entity Framework is losing tracking.
I am using Dev Express XAF WinForms to write an ERP system.
In practice I have found that my DBContext needs to have a DBSet for most of my business objects.
I am trying to figure out which tables should have a timestamp column for optimistic concurrency purposes.
For example I have
[NavigationItem("Sales")]
public class SalesOrder : BaseSalesHeader
{
public SalesOrder()
{
Lines = new List<SalesOrderLine>();
}
[Aggregated]
public virtual List<SalesOrderLine> Lines { get; set; }
}
[NavigationItem("Production")]
public class SalesOrderLine : BaseSalesProductTransactionLine
{
[Browsable(false)]
[System.ComponentModel.DataAnnotations.Required]
[RuleRequiredField(DefaultContexts.Save)]
[ForeignKey("SalesOrder_Id")]
public virtual SalesOrder SalesOrder { get; set; }
}
In my DBContext I have
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesOrderLine> SalesOrderLines { get; set; }
In my OnModelCreating I have
modelBuilder.Entity<SalesOrder>().HasMany(p => p.Lines).WithRequired(t => t.SalesOrder).WillCascadeOnDelete(true);
Sales Order Lines are accessible from 2 Menus
As part of a Sales Order, and as a Sales Order Line Item under the Production navigation item.
I think I should have the timestamp field in the SalesOrders table. Should I also have it in the SalesOrderLine table ?
Here is the linked question at Dev Express Support
Whether or not you want to apply optimistic concurrency (OC) for an entity is something we can't decide for you. But there are some things to consider:
It's not necessarily true that only entities that are exposed as DbSet will need OC. After all, any mapped entity can be changed when it's reachable through navigation properties. SalesOrder exposes SalesOrderLines by its Line property, so by all means you can create some UI that only modifies SalesOrderLines while it only receives a SalesOrder (including its lines) as input.
In Entity Framework (and other ORMs), a parent isn't marked as modified when one of its children is modified. If you save a SalesOrder with modified SalesOrderLines, there will only be update statements for the lines.
So, yes, you probably want to protect SalesOrderLine by OC as well. But also consider this:
OC isn't for free. When you add a RowVersion* column to a table (and map it as rowversion appropriately), Entity Framework will read its value after each insert or update. I've experienced that this may considerably harm performance in processes that update relatively many records (EF doesn't shine there anyway). Also, when a concurrency conflict occurs, EF will read the current values of the conflicting record(s) from the database.
I've seen applications where the performance impact from OC is mitigated by marking a parent object (having OC) as modified when any of its children is modified. I think that's rather contrived, but it may be something to consider.
* TimeStamp is a deprecated data type
Any table that could be updated by more than 1 user at the same time should really have some sort of timestamp associated with it. Personally, I put a timestamp on every table just to be doubly sure.
You can mark this timestamp field with a [Timestamp] attribute and EF will know what to do with it automatically.
I'm considering using entity framework database-first approach. The database in question uses various non-standard techniques, eg 'informal' foreign keys. I'd like to confirm that it's still possible to create a usable EF model from this database, even if all the relationships are not recognised?
Yes, you can do this. Generate the model from the database as normal, then modify the generated entities in order to introduce the relationships. You'll need to set a Null database initializer to tell EF it should not try and update the database to match its model:
Database.SetInitializer(new NullDatabaseInitializer<MyContext>());
There's no requirement for foreign keys to exist in the database to match your model - as long as the navigation properties have been added on the entities, EF will generate the correct SQL queries accordingly.
I would recommend the use of the [ForeignKey] attribute to clarify the names of your foreign key fields for when they don't conform to EF's expected patterns (or you could modify the Conventions accordingly). For example...
public class Child {
// ...
public int Parent_ID { get; set; } // <-- non-standard name
// Add these to introduce the navigation property without a formal relationship
[ForeignKey("Parent_ID")]
public virtual Parent Parent { get; set; }
}
I have used this approach on a MySQL database with no foreign keys at all.
I am new to Visual Studio so to start learning it I first of all downloaded a sample available at https://code.msdn.microsoft.com/ADPNET-Entity-Framework-2d1160cb and started working around it. Since I have fairly good knowledge of VB6 and SQL it did not take much time for me to understand the whole pattern the sample is based on. Had Microsoft given a detail explanation or a walk through of the sample it would have been much easier to understand the basics. However, I somehow managed to work around it and have build a small desktop application in wpf using Entity Framework and MVVM. But a point has come where I have got completely stuck up finding no way out. The problem is as under:
I have two tables. 1 Advocate and 2 Party. Table Advocate would contain names of advocates and would have a primary key. Similarly Party would have names and their respective primary keys.
Then I have another two tables 1. Case and 2 CaseDetail. Table Case would simply hold three columns: 1. CaseId 2. CaseNo and 3. Year. Table CaseDetail would have CaseDetailId as a primary key the CaseId as a Foreign Key. Now what I need is that a particular case could have multiple advocates and multiple petitioners. So the table CaseDetail would have two columns to hold advocateId and PartyId as a Foreign Keys.
If you look at the sample referred above you would not find how to deal with such a case. When I follow the pattern of the sample I get host of design time and runtime errors.
Anyways, after number of trials I have somehow manged to set the EF right but I doubt if it would serve any purpose since I need to have multiple instances of Petitioners and Advocates.
Here is the link to my edmx:
https://www.dropbox.com/s/rkarzod1lezdnqs/EDMX.png?dl=0
From the image it can be seen that I have four different foreign keys fldPetitioner, fldRespondent, fldAdvocate and fldSrAdvocate for which I too have navigation property to back track them which have multiplicity 0 or 1. Therefore, in such a scenario would I be able to have multiple instances on these columns?
Therefore, please suggest what strategy should be adopted in a scenario described above while developing WPF application using Entity Framework and MVVM.
I think it sounds like you're trying to use one-to-one relationships where there should be one-to-manys. Take a closer look at the relationship between Department and Employee from your linked MS sample. It results in '1 Department to many Employees'. This puts the DepartmentId against an entry in the Employee table, not the other way round, which is what I think you have at the moment. The analogous element from your question would be '1 CaseDetail to many Advocates'.
public class CaseDetail
{
//CaseDetail ID number
public int CaseDetailId { get; set; }
//...
//Any other properties go here
//...
//Navigation properties
public ICollection<Advocate> Advocates { get; set; }
/* Other collections would be executed similarly:
*
* public ICollection<Party> Petitioners { get; set; }
* public ICollection<Party> Respondents { get; set; }
*/
}
public class Advocate
{
//Advocate ID number
public int AdvocateId { get; set; }
//...
//Any other properties go here
//...
//Navigation properties
public int CaseDetailId { get; set; }
public CaseDetail CaseDetail { get; set; }
}
public class AdvocateConfiguration : EntityTypeConfiguration<Advocate>
{
public AdvocateConfiguration()
{
HasRequired(a => a.CaseDetail)
.WithMany(cd => cd.Advocates);
}
}
In the MS sample, you must have noticed that while entering data we assign Department to an employee although department to employee relationship is 1 to many. In my case the issue is that I want assign advocates to casedetail although the relationship casedetail to advocate is 1 to many. Here simply imagine a simple billing application where table invoice can be a master table having details in table invoicedetails where we can have multiple products as a foreign key. Considering the scenario please tell me whether or not there can be a derived entity with a navigation property to back track the products?
I have a database that uses natural keys (i.e. business oriented keys). Unfortunately, because of this, the primary keys for these objects may change over time.
I am currently researching the use of NHibernate for an O/RM for this database. However, in my testing I have noticed that there is no apparent way to change the primary key of an object and save it to the database.
For example, say I have a 'Business' object with a 'BusinessCode' as it's primary key:
public class Business
{
public string BusinessCode { get; set; }
public string Name { get; set; }
...
}
If I do a Get, change the primary key, and try and save it back to the database using NHibernate, I either receive an exception or unexpected results (depending on if I use Save(), Update(), or SaveOrUpdateCopy())
Business b = session.Get<Business>("BusinessCode1");
b.BusinessCode = "BusinessCode22";
session.Update( b );
So is something like this possible?
I understand that many NHibernate folks recommend using primary keys that do not change (i.e. identities). But I have a couple DB's that use natural keys. Thanks.
I'm actually kicking myself that I even asked this question because I can easily mitigate this by doing a delete-insert type of operation. This was more of a proof-of-concept with an existing database. Thanks for your input!
Have you tried using a composite-id?
Or Assigned Identifiers?
Is adding an Auto-incremented ID field totally out of the question?