Handling relations when mapping DTOs to EF entities - c#

In my DTOs, I send Ids instead of entire objects to assign/relate one object to another. The problem is my mapping code will need access to the database to handle this because my entity classes don't have BarId property.
public class FooDTO
{
public int FooId { get; set; }
public int BarId { get; set; }
}
public class Foo
{
public int FooId { get; set; }
public Bar Bar { get; set; }
}
This can probably be solved by adding additional BarId property to my entity class, that way I don't couple data access with my mapper.
But the question arises: if bar with specified id doesn't exist can this be handled in some reasonable way to return the custom error message?
public class Foo
{
public int FooId { get; set; }
public int? BarId { get; set; }
public Bar Bar { get; set; }
}
Is it fine to access database in my mapping code and handle these assignments manually or is it better to leave it to the ORM by explicitly adding a foreign key property (BarId) in my entity class?
Also see: https://learn.microsoft.com/en-us/ef/core/modeling/relationships#no-foreign-key-property
While it is recommended to have a foreign key property defined in the dependent entity class, it is not required.
It seems like adding foreign key property is recommended so I guess I will choose this route.

no, not fine. if you are accessing the db this is most definitely not mapping code.

Related

EF core Database specific columns to nested object

I have this:
public class Foo
{
public int Id { get; set; }
public Bar Bar { get; set; }
}
public class Bar
{
public int Something { get; set; }
public int SomethingElse { get; set; }
}
and my database is like this:
CREATE TABLE [Foo](
[Id] INT,
[Bar_Something] INT NOT NULL,
[Bar_SomethingElse] INT NOT NULL,
)
When I get the DB context with
public class DB: DbContext
{
public DbSet<Foo> Foo { get; set; }
}
Foo.Id is mapped correctly but Bar cannot be mapped with this error System.InvalidOperationException : The entity type 'Bar' requires a primary key to be defined.
I don't want to create Bar table and give its id as FK to Foo.
How can I map the columns Bar_Something and Bar_SomethingElse to Foo.Bar.Something and Foo.Bar.SomethingElse?
EF Core 2.0 and later support Owned entity types. By default, those are mapped using Table splitting.
In EF Core 2.1, you probably only need to add the [Owned] attribute to Bar, ie :
[Owned]
public class Bar
{
public int Something { get; set; }
public int SomethingElse { get; set; }
}
The owned type's properties will be mapped to fields in the same table named Property_OwnedProperty. In this case it will be Bar_Something and Bar_SomethingElse
Looks like someone designed the table with those requirements in mind.
In EF Core 2.0 you need to specify the owned type in the context configuration :
modelBuilder.Entity<Foo>().OwnsOne(p => p.Bar);
What you seem to be looking for is Table Splitting - the second entity of Bar will still need an ID field though it would be the same field that is used for the Foo object, meaning it will join them on a 1-1 basis perfectly.
This allows you to map the ID field of the table to multiple objects, then becoming both the principal and foreign key for the join.
you can read more about it an a quick example over Here as a pretty simple blog post demo.
This can also be done using the [Owned] attribute - the difference between using owned and simply mapping two objects to the same table is that an Owned object will only ever be a navigational property - so you wouldnt be able to just look for Bar you would always have to look for Foo and include Bar.
Depending on how you want them to behave (independent, or dependant) you have the two options for table splitting.
a primary key to be defined in your Bar class.
public class Bar
{
[Key]
public int Something { get; set; }
public int SomethingElse { get; set; }
}

Entity Framework Custom Navigational Properties

Is there a way to map below ClassA.BId to ClassB.BetaId ?
BetaId in ClassB is not primary key. Thus, mapping in following way end up in "The ForeignKeyAttribute is not valid" exception. Note that there is no foreign key relationship in these 2 classes. For some reason I must not map ClassA.BId to ClassB.Id because these 2 field is unrelated but I need to custom map ClassA.BId to ClassB.BetaId due to these 2 field is related. However, The Id in ClassB must remain as primary key.
Note: I'm using Entity Framework 6
[Table("A")]
public class ClassA{
[Key]
public int Id { get; set; }
public int BId { get; set; }
[ForeignKey("BId")]
public virtual B B { get; set; }
}
[Table("B")]
public class ClassB{
[Key]
public int Id { get; set; }
public int BetaId { get; set; }
}
If B.BetaID is unique you can declare it to be the Key. Otherwise EF Core supports Foreign Key properties referencing Alternate Keys. See https://learn.microsoft.com/en-us/ef/core/modeling/alternate-keys

Should I need to define two fields per foreign key in ASP.NET Core EF

Suppose that I need to have two tables named Wagons and WagonTypes. Obviously enough, each row in the Wagons table should reference to the correspoding WagonTypes record via foreign key.
Am I doing this right?
public class Wagons
{
public Guid Id { get; set; }
[Required]
public WagonTypes Type { get; set; }
}
public class WagonTypes
{
public Guid Id { get; set; }
[Required]
public string Name { get; set; }
}
Yeah, it works and all that but I don't unserstand why there's an additional field in the docs then:
public int BlogId { get; set; }
public Blog Blog { get; set; }
What's the point of having a BlogId field? Should I define it too?
You don't have to add the foreign key, but it's recommended because it makes your life easier.
Imagine you want to edit some row in table Wagons (for example property Name). You have to get the object, edit Name, then load property Type and then call SaveChanges. If you didn't load Type, EF would think you want to edit that Type too.
If you had public int TypeId{ get; set; } in your Wagons class, you could just get that object, directly edit Name and call SaveChanges without any further loading.

EF Code First Navigation Property to same table

I'm new to EF and struggling to implement the following scenario. I have an entity I'd like to have a navigation property to another of the same entity. E.g.
public class Stage {
public int ID { get; set; }
public int? NextStageID { get; set; }
public string Name { get; set; }
public virtual Stage NextStage { get; set;}
}
The only example I've found so far was where the entity had a parent / child relationship, i.e. the navigation property was an ICollection of the same entity. I tried adapting this but couldn't get it to work in my instance. Also, I only need it to be one way, i.e. the entity doesn't have a 'PreviousStage' property, just a 'NextStage' one. I'm configuring using Fluent API. Could someone advise if / how this can be achieved?
I am getting this error:
Unable to determine the principal end of an association between the types 'namespace.Stage' and 'namespace.Stage'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
Edit
Just realised in my slightly simplified example, I didn't show that NextStageID is optional (int?).
You can explicitly define the relation as follows:
public class Stage {
public int ID { get; set; }
public int NextStageID { get; set; }
public string Name { get; set; }
[ForeignKey("NextStageID ")]
public virtual Stage NextStage { get; set;}
}
you need to add a parentId and Parent navigation property
and Children navigation property so entity framework understands that is a recursive relation
check the answer in this stack Overflow link

Table with foreign keys missing members in generated class in edmx

I have a table in the database that has 4 foreign keys referencing to it. When I add the table to the edmx, the table and navigational properties are there. However, the foreign key ids from this table is missing and only the virtual objects are there.
This is the following table that is generated in the .tt file:
public partial class Device
{
public int SolutionId { get; set; }
public string SiteId { get; set; }
public string Name { get; set; }
public int SysId { get; set; }
public Nullable<int> SysType { get; set; }
public string SerialNumber { get; set; }
public Nullable<int> ParentId { get; set; }
public virtual DeviceModel DeviceModel { get; set; }
public virtual DeviceType DeviceType { get; set; }
public virtual SolutionApplication SolutionApplication { get; set; }
public virtual SolutionType SolutionType { get; set; }
}
There are a few members missing:
DeviceModelId, DeviceTypeId, SolutionApplicationId, and SolutionTypeId
Why is it missing? Is there any way to get those keys actually be part of the partial class?
using EntityFrameworks v6.0.2. Lazy Loading
In short, Entity Framework 'abstracts that away'.
Its clever enough to recognise that your FKs represent relationships and so allows you to work with the objects themselves. So instead of having you worry about checking the FK constraint, etc. for, say, SolutionTypeId - you just need to add a SolutionType object to your Device object and let Entity Framework sort it out. (Of course, this causes problems if you try to add a new SolutionType that violates the SolutionType PK so maybe you need to first find an existing object from the SolutionTypes table).
So, instead of thinking of it as a Device table linked to a SolutionType table via a FK - just think of it as a Device object with a SolutionType object as a property. EF sorts out the db for you when you save changes (assuming your model is accurate!)

Categories