Composite primary key scenario - primary-key

I need a many to many structure, but with an aggregate constraint.
What i'm trying to accomplish is done easily in pure sql, but since ActiveRecord discourages composite primary keys, i'm not sure how to accomplish what i need in recommended style.
Here is what i would have in pure sql:
table Project (ID int)
table Report (ProjectWideID nvarchar(50), ProjectID int, primary key (ProjectWideID, ProjectID))
table ChosenReport(ListOrder int, ProjectWideReportID, ReportID, primary key (ProjectID,ProjectWideReportID))
This means that a project has many reports.
Each report has an assigned id, which is unique inside a project.
Project has many chosen reports as an ordered list, each of them references a report in the same project by it's project-wide assigned report id.
But here is my ActiveRecord classes, and something is missing here.
[ActiveRecord]
public class Project
{
[PrimaryKey]
public int ID { get; set; }
[HasMany] IList<Report> Reports { get; set; }
[HasMany] IList<ChosenReport> ChosenReports { get; set; }
}
[ActiveRecord]
public class Report
{
[PrimaryKey]
public int ID { get; set; }
[BelongsTo("ProjectID")]
public Project ParentProject { get; set; }
// ... other properties
}
[ActiveRecord]
public class ChosenReport
{
// This one must be a key property
[BelongsTo("ParentProjectID")]
Project ParentProject { get; set; }
// This one must be a key property
[BelongsTo("ParentProjectID")]
Report ParentReport { get; set; }
// ... other properties
}
Now, since i have surrogate keys, i don't know how to constraint ChosenReport so it can't have reference to a report from different project. So i have to enforce constraints in domain. Do i have any other options for this with ActiveRecord?

The true ActiveRecord way of doing this would be making your classes inherit from ActiveRecordBase<T> and then overriding OnSave() and implementing your checks there. But I recommend implementing the checking logic in a NHibernate interceptor or event listener instead.

Related

EF Core composite foreign key and constraint

In my project I have noticed that I will be have a lot of dictionaries with the same structure:
shortcut
full name for tooltip
which will be used on many different business forms.
I started to thing that there is no sense to keep all of them in separate tables.
It is better to keep all of them in one table and provide an additional column (DictionaryType) which will separate them in the case of asking the database for data?
So one repository with such method
public class DictionaryEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public DictionaryType Type { get; set; }
}
public async Task<IEnumerable<DictionaryEntity> GetDictionaries(DictionaryType type)
{
return await _dbContext.Dictionaries.Where(d => d.DictionaryType == type).ToArrayAsync();
}
If new dictionaries appear, I need to only extend DictionaryType and I don't need to worry about database changes or repo/service/controller changes.
For now it is nice and easy, but... I would like to configure foreign key in business entities in that way:
public class CarEntity
{
public Guid Id { get; set; }
public Guid ModelTypeId { get; set;}
public DictionaryEntity ModelType { get; set;}
public Guid PetrolTypeId { get; set;}
public DictionaryEntity PetrolType { get; set;}
}
How to configure in EF Core, foreign key in that way where:
CarEntity.ModelTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.ModelType ?
CarEntity.PetrolTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.PetrolType ?
I read, that there is something like a composite foreign key, so I could do FK on { dict.Name, dict.Type } but it demands from me to keep in CarEntity as many properties as composite foreign key have.
Is there a chance to do unique constraint across multiple tables ?
Something like this:
modelBuilder.Entity<CarEntity>()
.HasCheckConstraint("CK_ModelType", "[ModelTypeId] IS NOT NULL AND [Document].[Type] = 'ModelType'", c => c.HasName("CK_ModelType_Dictionary"));

How does migrationBuilder determine which indexes to create?

This is using asp.net core 2.0, EF, visual studio 2017, sql server 2016, and creating a db migration via package manager console using 'add-migration' tool within the Package Manager Console.
I have a simple many-to-many relationship configured as below, 2 tables and a third 'joining table':
public class TblTrack
{
public int ID { get; set; }
...
//Navigation properties
public List<TblProductItem> ProductItems { get; set; }
}
public class TblProduct
{
public int ID { get; set; }
...
//Navigation properties
public List<TblProductItem> ProductItems { get; set; }
}
public class TblProductItem
{
[Key]
[Required]
public int ProductID { get; set; }
[Key]
[Required]
public int TrackID { get; set; }
//Navigation properties
public TblProduct Product { get; set; }
public TblTrack Track { get; set; }
}
This is from the migration (generate in PMC) to create the joining table:
migrationBuilder.AddPrimaryKey(
name: "PK_tbl_ProductItems",
table: "tbl_ProductItems",
columns: new[] { "ProductID", "TrackID" });
migrationBuilder.CreateIndex(
name: "IX_tbl_ProductItems_TrackID",
table: "tbl_ProductItems",
column: "TrackID");
Please could someone explain:
What's the purpose of the index IX_tbl_ProductItems_TrackID?
Why was an index created for TrackID but not for ProductID?
Is there some other setting that determines which indexes will be created in the migration?
By default EF automatically creates Index (non-unique) on each property that is a foreign key reference.
Make sure that EF correctly created relation between TblProduct and TblProductItem(for example in SQL Server by expanding keys) - if not, specify relation explicitly using Fluent Api.
Regarding other setting you can require creating indexes using method in your Context class, but that index should be auto generated if foreign key relation is set.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TblProductItem>()
.HasIndex(e => e.TrackID);
}
I'm struggling with the same thing. I found out that if I reversed the order of the keys (using Fluent, however) it would make an index for the second column instead.
So to me, it seems like there's a bug in the framework when using composite keys. It is the ForeignKey annotation that causes the index to be made, but in this process it seems to believe that the primary key is the FIRST column only (in that case, no extra index needed for a "primary key" column), so it only creates an index for the second. But the primary key is composite, so it should probably create an index for the first column too.
A workaround (if you really want the first column to be indexed too) is to do what's suggested in the accepted answer. Should the bug (AFAIK) be fixed later, I don't think it would cause a problem by trying to create an extra index or anything.

Entity Framework Core Code First Model Navidation Properties

I have a Web API that uses entity framework. I have several tables there were created using the code first setup. My Competitions class is defined below.
Everything works great and I'm able to get my Competitions table data along with all the data in the navigation properties that are returning a collection. However, I'm not able to get any values for the CompetitionTypes and Users navigation properties. OwnerId references UserId in the Users table.
How would I get the linked data in my CompetitionTypes and Users table? I basically want the same thing as the three collection navigation properties, except that CompetitionTypes and Users would only return one row.
public partial class Competitions
{
[Key, Required]
public int CompetitionId { get; set; }
public int CompetitionTypeId { get; set; }
public int OwnerId { get; set; }
public string CompetitionName { get; set; }
public CompetitionTypes CompetitionTypeId { get; set; }
public Users UserId { get; set; }
public ICollection<Participants> Participants { get; set; }
public ICollection<ResultStats> ResultStats { get; set; }
public ICollection<Results> Results { get; set; }
}
}
EF auto-matches FK properties with navigation properties based on conventions. Namely, it expects FK properties to be named the same as navigation properties, just with Id at the end. In other words, for it to automatically match up OwnerId, you'd need a navigation property like:
public User Owner { get; set; }
Since your navigation property is UserId, it's actually looking for a property named UserIdId.
If you don't want to follow conventions, then you must either use the ForeignKey attribute or fluent config to tell EF which property belongs with which.
That said, there's some pretty major issues with your naming of things here. First, entities should always be singular User, not Users. Second, you should not have navigation properties that end with Id: e.g., User, not UserId. Only actual PK or FK properties should end with with Id. Finally, don't prefix properties on your entity with the entity name. This last one is mostly for readability. Which is more natural: competition.Id or competition.CompetitionId? Likewise with CompetitionName; it should just be Name. And, for what it's worth, you don't need Required for either a primary key or a non-nullable type (such as int). In either case, the property is required by default.

Generating Primary key without set it as key

When I create a table in entity framework, i am not set any key in the table. But, when the table created the id field in the table set as key, Why?
public class EntityBase
{
public long Id { get; set; }
public DateTimeOffset? DeletedOn { get; set; }
public string RefId { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
As mentioned here Entity framework automatically identifies the primary key based on ideal naming like Id in your case :-
As detailed in document :-
Other default conventions supported by EF include the ability to
automatically identify primary-key and foreign keys based on common
naming patterns (for example: an ID or DinnerID property on the Dinner
class will be inferred as the primary key). EF also includes smart
conventions for wiring-up association relationships between models.
For more information :-
http://blogs.msdn.com/b/efdesign/archive/2010/06/01/conventions-for-code-first.aspx

Fluent nHibernate - Wrong column name when self reference

The mapping on foreign key are made with the wrong name. Why?
Here's my classes:
The order of the properties seems to be important:
public class Person
{
public virtual Person Mother { get; set; }
public virtual IList<Item> Items { get; set; }
public virtual Person Father { get; set; }
}
public class Item
{
public virtual string Name { get; set; }
}
Here's the mapping with Fluent Nhibernate
AutoMap.AssemblyOf<Person>(new CustomAutomappingConfiguration())
When I look to the database, the foreign key in the table seems to be the name of the first property with the type Person after the property Items. Here's the SQL generated to create the table:
CREATE TABLE "Item" (Id integer primary key autoincrement
, Name TEXT
, Father_id BIGINT
, constraint FKC57C4A2B4586680 foreign key (Father_id) references Patient)
Thank you in advance for your help ;)
The solution I've found is to override the configuraton like this:
AutoMap.AssemblyOf<Person>(new CustomAutomappingConfiguration())
.Override<Person>(m => m.HasMany<Item>(x => x.Items).KeyColumn("Patient_Id"))
Does exist any solution to let the auto mapping work seamlessly? And how Fluent nHibernate works to choose the name of the foreign key's column?