Entity Framework mapping list of ids - c#

I am in a strange situation right now, I have two entities:
public class Proyect
{
int id;
List<int> stages;
}
public class Stage
{
//PK, not FK to proyect
int id;
}
I know that this is not the best way to model this kind of relation (n->1)
but it was done this way and we can't change it.
Does someone know, how do I relate this entities (notation or overriding onModelCreation)?
We are using c#, ET4, VS2012, WS8.

I like to use Data Annotations for simple relationships. You must specify your key field on the Proyect table, and your foreign key on the Stage table. In the Proyect table, you should have a list of Stages, not ints, since you are relating to the Stage object. You can use the virtual keyword to use lazyloading on your related entities.
If you really need a list of type int, containing your stage Ids, just use an unmapped property.
public class Proyect{
[Key]
public int id { get; set;}
public virtual List<Stage> stages { get; set;}
[NotMapped]
public virtual List<int> stageIds {
get {
return stages == null ? null : stages.Select(t => t.id).ToList();
}
}
}
public class Stage{
public int id { get; set;}
[ForeignKey("id")]
public virtual Proyect Proyect { get; set;}
}

Related

Duplicate entities when setting state within a collection in Entity Framework

I have a solution which uses Entity Framework to insert invoices to a database table. These invoices reference an order, which in turn also references an order item collection.
In this instance I am trying to add an order to the database, however the code is inside a new DbContext and so I need to attach the order and order items to the context, as these already exist in the database and shouldn't be re-added.
I've cut down the model properties for the sake of demonstration:
public class Invoice {
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceId { get; set; }
public string OrderNumber { get; set; }
...
public virtual List<InvoiceLineItem> LineItems { get; set; }
}
public class InvoiceLineItem {
[Key]
public int Id { get; set; }
...
public ShopifyOrderItem { get; set; }
}
public class ShopifyOrder {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public int OrderNumber { get; set; }
...
public OrderInvoiceStatus InvoiceStatus { get; set; }
public virtual List<ShopifyOrderItem> OrderItems { get; set; }
}
public class ShopifyOrderItem {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
...
[Required]
public virtual ShopifyOrder ShopifyOrder { get; set; }
}
In the invoice engine, I'm running the following code for each invoice to add it to the database:
ShopifyOrder order = await db.ShopifyOrders.SingleOrDefaultAsync(x => x.OrderNumber.ToString() == inv.OrderNumber);
if (order != null) {
// Attach marketplace entity to the invoice to avoid duplicate primary key exceptions
db.Marketplaces.Attach(inv.Marketplace);
db.Invoices.Add(inv);
order.InvoiceStatus = OrderInvoiceStatus.InProgress;
}
I've tried a number of methods to try and attach the states, however they all throw errors.
inv.LineItems.ForEach(li => {
db.Entry(li).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem.ShopifyOrder).State = EntityState.Modified;
});
The above code returns the following error on save:
EntityFramework: Saving or accepting changes failed because more than one entity of type 'TorroModels.ShopifyOrder' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model.
What is the best way to attach the LineItems/ShopifyOrderItems without trying to attach the ShopifyOrder connected property multiple times?
Sorry to say but it seems that you need to follow the best practice first when constructing a relationship. You may follow this link :
http://www.entityframeworktutorial.net/entity-relationships.aspx
In short :
Avoid using only "Id" in every entity, or you can use attributes to map between the physical name and the property name
It seems that you have circular references here, so maybe you could simplify it first
Next, you can read this link :
http://www.entityframeworktutorial.net/EntityFramework5/attach-disconnected-entity-graph.aspx
if you need to know more about what's the best practice of attaching entities, but in my opinion, just don't abuse this feature, because using normal CRUD should be sufficient most of the time.
I'm sorry I cannot help you more than this, because of lack of information I may need, and with my reputation I still cannot comment directly in your post to ask for it.

SQLite-Net Extensions not inserting in cascade in some cases

I am using SQLite-Net PCL together with SQLite-Net extensions for the development of an application using Xamarin.
In my model I have an entity (let's call it A) which is connected to other four entities through one-to-many relationships (that are represented as lists in the model). In order to populate the tables recursively when inserting an object of A in the database I have defined the relations to use Cascade on both read, insert and delete.
In order to test if I did everything correctly I created an object of type A and populated the including lists, and finally I have inserted it into the database. The strange thing is that, for 2 of the 4 including lists the insertion went well, and all the connected objects are inserted. For other 2, instead, only the first object of the list is inserted in the database. To be clear, I am checking the database content directly with a db browser.
The following is an example of one of the objects for which only the first element of the list is inserted.
public class Username : Entity
{
public string Name
{
get;
set;
}
[ForeignKey(typeof(A))]
public int AId
{
get;
set;
}
public Username(string username)
{
Name = username;
}
}
This is instead one of the objects for which the insertion is correct.
public class AnAddress: Entity
{
public string Address
{
get;
set;
}
public AddressType Type
{
get;
set;
}
[ForeignKey(typeof(A))]
public int AId
{
get;
set;
}
}
To be clear, the base object Entity contains the definition of the primary key:
public abstract class Entity
{
[PrimaryKey, AutoIncrement]
public int Id
{
get;
set;
}
public Entity()
{
Id = -1;
}
}
And this is the way the relationships are defined:
public class A : Entity
{
public string Name
{
get;
set;
}
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<AnAddress> Addresses
{
get;
set;
}
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<Username> Usernames
{
get;
set;
}
}
I then create an A object by initialising it with two lists (List and List) in the same identical way.
I finally insert the object in the database with
c.InsertWithChildren(entity, recursive: true));
Where entity is of type A and c is the connection object.
Do you have any clue about the motivation of this strange behaviour?

Entity Framework 6 - 0..1 RelationShip Mapping

I have two classes:
public class Report
{
public int IdReport {get;set;}
public int IdModel {get;set;}
public Model MyModel {get;set;}
}
public class Model
{
public int IdModel {get;set;}
public Report MyReport {get;set}
}
I have this configuration class:
public class ReportConfiguration : EntityTypeConfiguration<Report>
{
HasOptional(c => c.Model).WithOptionalPrincipal(d => d.Report)....
}
This is where I got stuck, how can get the HasForeignKey(c => c.IdModel) configuration
I need this because we have a form using binding source, and a report can have or not a model(since we make dynamic reports).
I dont wanna create a fake foreign key, like creating a property and on report insert, I set this property value with primary key from the model. This is a way I found to fill the bindingsource with correctly value to be bounded with the combobox value edit.
I see that the navigation propertu MyModel.IdModel can provide this funcionality, but does binding source can accomplish this approach ?
I'm not sure that this is exactly what you need but this will create a nullable foreign key relationship from Report to Model and vice versa:
public class Report
{
public int ReportId { get; set; }
public int? ModelId { get; set; }
public Model Model { get; set; }
}
public class Model
{
public int ModelId {get; set;}
public Report Report { get; set; }
public int ReportId { get; set; }
}
public class ReportConfiguration : EntityTypeConfiguration<Report>
{
public ReportConfiguration()
{
this.ToTable("Report");
this.HasOptional(m => m.Model).WithMany().HasForeignKey(m => m.ModelId).WillCascadeOnDelete(false);
}
}
Hope it helps.
With your mapping, Report is the principal entity, which means that Model has the foreign key. So you wouldn't be able to set a ModelId in Report anyway. You have to set the Model in stead.
Technically, this is not a big deal. You can populate a combobox (or a bindingsource) with Models, not set a ValueMember and bind the SelectedItem.
Performance-wise it probably doesn't really matter either, unless Model has very wide records and you intended to only select its Id and Name properties. Now you have to fetch the full objects from the database.
I've always wondered why the 1-1 API doesn't allow defining a foreign key association (i.e. a reference and primitive foreign key pair) but forces you to work with an independent association (reference only). So far, the reason is not clear to me. It looks to me that, in this case, Model could have had a ReportId exposed in the class model.

Filling Foreign Key Object in Entity Framework 4

I am using EntityFramework for the first time and maybe this question is so simple...I've used code first method..I have a Class Personnel which looks like this:
public class Personnel
{
public string Id { set; get; }
public int Code { set; get; }
public string Name { set; get; }
public int Type { set; get; }
public JobTitle Title { set; get; }
}
and the JobTitle class:
public class JobTitle
{
public string Id { set; get; }
public int Number { set; get; }
public string Title { set; get; }
public List<Personnel> Personnels { set; get; }
}
which the last property in Personnel Class is a foreign key in personnel table of course..my problem is when I want to retrieve all personnels ( or a personnel ) from DB using lambda expression..the foreign key object is null..the lambda expression is like below:
Context.ContextInstance.Personnels.ToList();
and if I change the expression to this the foreign key object is not null any more.
Context.ContextInstance.Personnels.Include("Title").ToList();
is it the right way??..is there any better way??..I supposed that EF will automatically understand that!!!!..if there are more than 1 FK then I have to use Include for all of them?? please help me to understand.
Thanks
This is due to lazy loading. When you call Context.ContextInstance.Personnels.ToList(); this will fetch all personnel's but Title will not fetch until it get instanced, so make it virtual to get it.
or, you can disable lazy loading by
public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext") {
this.Configuration.LazyLoadingEnabled = false;
}
Doing this will get all related data from context. Using "include" is loading on demand, when you specify properties you want to query.
Virtual keyword allows entity framework runtime create dynamic proxies for your entity classes and their properties, and by that support lazy loading. Without virtual, lazy loading will not be supported, and you get null on collection properties.
If your JobTitle property would be defined as virtual, you wouldn't need to use include.
It's really good explained here: Entity Framework 4.1 Virtual Properties

How do I delete related objects in Entity framework code first database?

DBContext class is
public class VGDB : DbContext
{
public DbSet<Planet> Planets { get; set; }
}
And model looks like:
public class Planet
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
public List<Building> Constructions { get; set; }
}
public class Building
{
[Key]
public int Id { get; set; }
public decimal Lvl { get; set; }
public string Type { get; set; }
}
Repository class:
public class VGDBRepository
{
private readonly VGDB _vgdb;
...
public void RemovePlanets()
{
foreach (Planet planet in _vgdb.Planets)
{
_vgdb.Planets.Remove(planet);
}
_vgdb.SaveChanges();
}
...
}
Entity Framework creates database with two tables: Planets and Buildings, related by Planet_Id field. When I call RemovePlanets() method of my VGDBRepository class it removes planets record from Planets table and sets Planet_Id field of all buildings, related with deleted planets, in Buildings table to null but not deletes them, so I have redundant records in database. I use code-first strategy to create database. How can I force Entity Framework to remove such type of related data???
You would need to cascade your deletes.
Take a look at this:
Stackoverflow Example Cascade Deletes
And this:
Msdn Code First with Enabling Cascade Deletes
I had the exact same problem and I recently figured out how to fix it so I thought I'd just add on to the answer provided by Dima.
The code that you have above for Planet and Building look very similar to how I had my related objects set up; it made sense to me to set up the relations like that. Moreover, the tables seemed to generate correctly with a FK reference back to the parent table. Like you, when I deleted my parent record (Planets, in your case), the child records (Buildings, in your case) still stuck around but the FK field had the parent ID removed so that it just had a null value. The objects were removed from the in memory collection, though, so things were getting out of sync. The thing that was really confusing to me was that Entity Framework Code First is supposed to, by default, cascade deletes like this and I didn't understand why my deletes weren't cascading.
After some digging around, I found that I had to set up a Foreign Key Association within the child class so that Entity Framework did the cascade delete correctly. So you would need to change your code to look like this:
public class Planet
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
public List<Building> Constructions { get; set; }
}
public class Building
{
[Key]
public int Id { get; set; }
public decimal Lvl { get; set; }
public string Type { get; set; }
//Add these two properties to create the Foreign Key Association
public int planetID { get; set; }
public Planet planet { get; set; }
}
As soon as I added the two properties and did an automigration on my database, the deletes cascaded just like I expected them to. I'm still a little unclear on why this needs to be done, but that's a subject for a separate post... I just thought that I'd share what had gotten this working for me.
Eager loading may help you. Otherwise, enable lazy loading.
foreach (Planet planet in _vgdb.Planets)
{
_vgdb.Planets.Include(p=>p.Constructions).Remove(planet);
}

Categories

Resources