EF-Code First navigation property foreign key in complex type - ef-code-first

I have complex type for Audit fields
My complex type:
[ComplexType]
public class AuditData {
[Column("CreatorUserId")]
public int? CreatorUserId { get; set; }
public DateTime? CreationTime { get; set; }
[Column("ModifierUserId")]
public int? ModifierUserId { get; set; }
public DateTime? ModificationTime { get; set; }
}
My base Entity (all other inherti this one) has AuditData property:
public abstract class Entity : IEntity, IAuditedEntity, INotifiedDbContextBeforeSave
{
// Summary:
// Unique identifier for this entity.
public int Id { get; set; }
public bool IsActive { get; set; }
public int Old_Id { get; set; }
public string Old_TableName { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
public AuditData AuditData { get; set; }
// can this 2 lines below work as navigation property with foreign key in complex type
public virtual User CreatorUser { get; set; }
public virtual User ModifierUser { get; set; }
//... other fields
}
I have 2 navigation properties CreatorUser and ModifierUser.
I know you cant have navigation property in ComplexType but can my navigation property on entity be mapped with foreign key in complexType
something like:
[ForeignKey("CreatorUserId")] // --> should point to AuditData.CreatorUserId
public virtual User CreatorUser { get; set; }
becouse CreatorUserId will be property in every entity but EF is not aware of it.
Mybe there is solution in fluent API ?

The official documentation says:
Complex types are non-scalar properties of entity types that enable scalar properties to be organized within entities. Like entities, complex types consist of scalar properties or other complex type properties. Because complex types do not have keys, complex type objects cannot be managed by the Entity Framework apart from the parent object.
It follows that that complex types can not participate in any relations among entities, so they can't contain foreign keys

Related

.NET EF Inheritance without keys or constraints

It is possible to inherit from a type in dotnet EF without inherit the keys, indexes, etc?
I have these types:
public class Product : IEntity<long>
{
public long Id { get; set; }
public string Name { get; set; }
}
public class ProductVersion : Product
{
[Key]
public int ProductVersionId { get; set; }
public DateTime CreatedAt { get; set; }
}
I want ProductVersion to inherit all the properties from Product without creating any keys, constraints or navigation properties from the parent, just have the same properties and if are required or not, basically create a copy of the table columns.
The way you have it set up should remove the key constraint:
https://www.tektutorialshub.com/entity-framework-core/data-annotations-key-attribute-in-ef-core/
Adding [NotInherritedAttribute] should get rid of any of restraints you add:
https://learn.microsoft.com/en-us/dotnet/api/system.attributeusageattribute.inherited?view=net-6.0
[NotInheritedAttribute]
public class ProductVersion : Product{
[Key]
public int ProductVersionId { get; set; }
public DateTime CreatedAt { get; set; }
}

.Net Core Foreign Key Field always null

We have a .net core api project. Foreign Keyed model always returning null from select queries.
DBContext is initialized with UseLazyLoadingProxies option.
Foreign key relation is defined in the table ContentTopic.
Foreign key is defined as ContentTopic->TopicId = Topic->Id
In the sample below Topic always return null.
services.AddDbContext<VaultContext>(options =>options.UseLazyLoadingProxies().UseSqlServer(Configuration.GetConnectionString("DBContext")));
[Table("ContentTopic")]
public class ContentTopic
{
[Key]
public long Id { get; set; }
public long TopicId { get; set; }
public long ContentId { get; set; }
public DateTime CreateDate { get; set; }
public bool IsInBody { get; set; }
[ForeignKey("TopicId")]
public virtual Topic Topic { get; set; }
}
UseLazyLoadingProxies extension must be called from DBContext in OnConfiguring method not from Startup.cs

Tree structure with reference to root in Entity Framework

I'm trying to model a tree structure for orders in Entity Framework. Right now I've go the following:
public class ProjectModel
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CustomerId { get; set; }
public virtual List<ProjectNode> Nodes { get; set; }
}
public class ProjectNode
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Path { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual List<ProjectNode> Children { get; set; }
}
What I need to be able to do is get a reference to the root ProjectModel at any level of ProjectNode in order to authorize a given user actually having permission to view and change the project which contains the ProjectNode.
public class ProjectNode {
public int ProjectId { get; set; } //<-- this
...
public class ProjectModel {
[Key]
public int Id { get; set; } //<-- containing the value of this
}
My question is whether its possible to have a theoretical ProjectId property populated at every level of the tree structure, or if I need to set it manually.
I had something working that at first blush appeared to allow this functionality, but upon further investigation only populated the ProjectId for ProjectNodes contained in the ProjectModel's Nodes property.
It seems to me like it would be super inefficient to recurse backwards through the structure to get to the root.
Credit due to #TestWell for this answer -
Apparently, all I needed to do for EF to automatically populate the ProjectId property on the ProjectNode was to change the name of the Id property in ProjectModel to ProjectId.
Unfortunately, this doesn't appear to work if I add a CustomerId property to the ProjectNode that I would like automatically populated from the property of the same name on the node's root ProjectModel, which I realized is the more efficient solution to what I'm trying to do.

Is it OK to declare a DBSet in the context for both a base table and a derived table?

I have a SalesOrder table which inherits from a SalesDocument table using Table Per Type Inheritance
The ( simplified) table classes are;
[Table("SalesDocumentHeaders")]
public abstract class SalesDocumentHeader
{
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public virtual DateTime? DocumentDate { get; set; }
[Required]
public String ReferenceNumber { get; set; }
}
[Table("SalesOrders")]
public class SalesOrder : SalesDocumentHeader
{
[Required]
public String CustomerOrderNumber { get; set; }
public DateTime? DeliverBy { get; set; }
public virtual SortableBindingList<SalesOrderLine> Lines { get; set; }
}
The context contains
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesDocumentHeader> SalesDocumentHeaders { get; set; }
It doesn't strictly need the SalesOrders DBSet, since SalesOrder inherits from SalesDocumentHeader however I find it convenient.
It seems to work OK, but I am worried that there are 2 ways of reaching the same record , am I doing something wrong?
Usually you only need to keep the DBSet for the base table. This helps when you have multiple derived tables (call them A and B) and you need to decide the actual type dynamically.
For example if you have another entity which references type A or B (like a user can have different types of contact information), you can reference the base table and EF will resolve the correct concrete type at runtime. Though of course this adds some extra casting code.

ASP.NET MVC 3 EntityType has no key defined

I want to display customer information.
Then I created some classes; Customer, Delivery, Order, OrderLine, Product, and rentalDB.
rentalDB class sets 5 DbSet of Product, Customer, Order, OrderLine, and Delivery.
When I make UserController with list view, I cannot display the customer information, and it takes errors:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'OrderLine' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntityType: : EntityType 'Delivery' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �OrderLine� is based on type �OrderLine� that has no keys defined.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �Delivery� is based on type �Delivery� that has no keys defined.
I don't know why these entities require key?
I have no idea for this error..
Could you help me?
--UserController.cs--
namespace MvcApplication2.Controllers
{
public class UserController : Controller
{
//
// GET: /User/
rentalDB _db = new rentalDB();
public ActionResult Index()
{
var model = _db.Customer;
return View(model);
}
}
}
--Delivery.cs in Models folder--
namespace MvcApplication2.Models
{
public class Delivery
{
public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
--OrderLine.cs in Models folder--
namespace MvcApplication2.Models
{
public class OrderLine
{
public int basketId { get; set; }
public int productId { get; set; }
public int quantity { get; set; }
}
}
In order to use the entity framework, every entity needs a key. This is how EF tracks objects in its cache, posts updates back to the underlying data store, and links related objects together.
Yours objects already have keys, you just need to tell the EF about them:
namespace MvcApplication2.Models
{
public class Delivery
{
[Key] public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
When you use an ORM (object-relational mapper) framework like NHibernate or Entity framework that helps you map a relational database to an object model you need something that will let you make a meaningful relation between your objects in memory and rows of data in your database and that thing is a key (id as NHibernate call it) and usually that's the natural way that RDBMS track records using a Primary key (usually you use DB primary key as the key of your object)
When you check to see if two objects are equal using == operator you are checking that those objects have the same reference (or address in memory). This kind of equality is not very helpful when you are using an ORM .You can load multiple instances of a record in memory with different references so that it's impossible to check the equality of objects by their references .That's when checking equality by value come into play and keys have the main role in this play.

Resources