admin管理员组文章数量:1355570
I have works
, users
and likes
. A like
is a connection between a user
and a work
. The work
was created by a user
.
I would like to have tables like this:
public class DbUser
{
public Guid Id { get; set; }
public ICollection<DbWork> Works { get; set; } = new List<DbWork>();
public ICollection<DbLike> Likes { get; set; } = new List<DbLike>();
}
public class DbWork
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
//public DbUser User { get; set; } this doesn't work
public ICollection<DbLike> Likes { get; set; } = new List<DbLike>();
}
public class DbLike
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public DbUser User { get; set; }
public Guid WorkId { get; set; }
public DbWork Work { get; set; }
}
I can't set up all the connections.
My current Fluent API is:
public class DbUserConfiguration : IEntityTypeConfiguration<DbUser>
{
public void Configure(EntityTypeBuilder<DbUser> builder)
{
builder
.HasKey(u => u.Id);
//builder
// .HasMany(u => u.Works)
// .WithOne(w => w.User)
// .OnDelete(DeleteBehavior.NoAction);
builder
.HasMany(u => u.Likes)
.WithOne(w => w.User)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class DbWorksConfiguration : IEntityTypeConfiguration<DbWork>
{
public void Configure(EntityTypeBuilder<DbWork> builder)
{
builder.HasKey(w => w.Id);
builder.HasMany(w => w.Likes)
.WithOne(l => l.Work)
.HasForeignKey(l => l.WorkId)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class DbLikeConfiguration : IEntityTypeConfiguration<DbLike>
{
public void Configure(EntityTypeBuilder<DbLike> builder)
{
builder.HasKey(u => u.Id);
}
}
There are two keys in the work
table: UserId
and DbUserId
error if you uncomment comments:
Annotations are simple for configuration like Keys, FKs where fluent is suited to more complex mappings like the one-to-many/many-to-many. Some general tips are to protect setters for PKs and FKs to avoid code from accidentally trying to change these. Also remove setters for collection navigation properties. Setting these inappropriately can cause issues. When it comes to EF and resolving relationships by convention an important detail that may have tripped up your configuration is that by convention when linking FKs to their navigation property, EF defaults to resolving these by type name, not property name. If your entity type is "DbUser" EF will look for "DbUserId" or "DbUser_Id", not "UserId" so you need to explicitly set these mappings. (Annotations or fluent config)
You will need to be very careful with tracking references to these entities as the NoAction delete behavior will result in exceptions being raised if EF interprets your code as removing entities or setting navigation properties to #null. Often errors occurring when updating or creating rows involving navigation properties are due to bad assumptions around tracked/untracked references rather than mapping.
Database with UserId and DbUserId with commented code:
I have works
, users
and likes
. A like
is a connection between a user
and a work
. The work
was created by a user
.
I would like to have tables like this:
public class DbUser
{
public Guid Id { get; set; }
public ICollection<DbWork> Works { get; set; } = new List<DbWork>();
public ICollection<DbLike> Likes { get; set; } = new List<DbLike>();
}
public class DbWork
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
//public DbUser User { get; set; } this doesn't work
public ICollection<DbLike> Likes { get; set; } = new List<DbLike>();
}
public class DbLike
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public DbUser User { get; set; }
public Guid WorkId { get; set; }
public DbWork Work { get; set; }
}
I can't set up all the connections.
My current Fluent API is:
public class DbUserConfiguration : IEntityTypeConfiguration<DbUser>
{
public void Configure(EntityTypeBuilder<DbUser> builder)
{
builder
.HasKey(u => u.Id);
//builder
// .HasMany(u => u.Works)
// .WithOne(w => w.User)
// .OnDelete(DeleteBehavior.NoAction);
builder
.HasMany(u => u.Likes)
.WithOne(w => w.User)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class DbWorksConfiguration : IEntityTypeConfiguration<DbWork>
{
public void Configure(EntityTypeBuilder<DbWork> builder)
{
builder.HasKey(w => w.Id);
builder.HasMany(w => w.Likes)
.WithOne(l => l.Work)
.HasForeignKey(l => l.WorkId)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class DbLikeConfiguration : IEntityTypeConfiguration<DbLike>
{
public void Configure(EntityTypeBuilder<DbLike> builder)
{
builder.HasKey(u => u.Id);
}
}
There are two keys in the work
table: UserId
and DbUserId
error if you uncomment comments:
Annotations are simple for configuration like Keys, FKs where fluent is suited to more complex mappings like the one-to-many/many-to-many. Some general tips are to protect setters for PKs and FKs to avoid code from accidentally trying to change these. Also remove setters for collection navigation properties. Setting these inappropriately can cause issues. When it comes to EF and resolving relationships by convention an important detail that may have tripped up your configuration is that by convention when linking FKs to their navigation property, EF defaults to resolving these by type name, not property name. If your entity type is "DbUser" EF will look for "DbUserId" or "DbUser_Id", not "UserId" so you need to explicitly set these mappings. (Annotations or fluent config)
You will need to be very careful with tracking references to these entities as the NoAction delete behavior will result in exceptions being raised if EF interprets your code as removing entities or setting navigation properties to #null. Often errors occurring when updating or creating rows involving navigation properties are due to bad assumptions around tracked/untracked references rather than mapping.
Database with UserId and DbUserId with commented code:
Share Improve this question edited Apr 2 at 7:34 Pavel Kostin asked Mar 30 at 2:01 Pavel KostinPavel Kostin 111 silver badge3 bronze badges 4 |1 Answer
Reset to default 2There are two separate mappings to set up on the user. Works and Likes. Works is a regular one-to-many relationship, where Likes is effectively a many-to-many. You can approach this two ways, either a standard many-to-many if a "Like" is just a joining table between User and Work, or though set up as a one-to-many-to-one using the joining entity if you want to expose additional columns on the Like table. (I.e. comments, rating, etc.)
Assuming a one-to-many-to-one:
public class DbUser
{
[Key]
public Guid Id { get; protected set; }
public ICollection<DbWork> Works { get; } = [];
public ICollection<DbLike> Likes { get; } = [];
}
public class DbWork
{
[Key]
public Guid Id { get; protected set; }
public Guid UserId { get; protected set; }
[ForeignKey(nameof(UserId))]
public DbUser User { get; set; }
public ICollection<DbLike> Likes { get; } = [];
}
public class DbLike
{
[Key]
public Guid Id { get; protected set; }
public Guid UserId { get; protected set; }
[ForeignKey(nameof(UserId))]
public DbUser User { get; set; }
public Guid WorkId { get; protected set; }
[ForeignKey(nameof(WorkId))]
public DbWork Work { get; set; }
}
public class DbUserConfiguration : IEntityTypeConfiguration<DbUser>
{
public void Configure(EntityTypeBuilder<DbUser> builder)
{
builder
.HasMany(u => u.Works)
.WithOne(w => w.User)
.HasForeignKey(w => w.UserId)
.OnDelete(DeleteBehavior.NoAction); // Be prepared for exceptions if deleting user entities.
builder
.HasMany(u => u.Likes)
.WithOne(l => l.User)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class DbWorksConfiguration : IEntityTypeConfiguration<DbWork>
{
public void Configure(EntityTypeBuilder<DbWork> builder)
{
builder.HasKey(w => w.Id);
builder.HasMany(w => w.Likes)
.WithOne(l => l.Work)
.OnDelete(DeleteBehavior.NoAction);
}
}
Annotations are simple for configuration like Keys, FKs where fluent is suited to more complex mappings like the one-to-many/many-to-many. Some general tips are to protect setters for PKs and FKs to avoid code from accidentally trying to change these. Also remove setters for collection navigation properties. Setting these inappropriately can cause issues. When it comes to EF and resolving relationships by convention an important detail that may have tripped up your configuration is that by convention when linking FKs to their navigation property, EF defaults to resolving these by type name, not property name. If your entity type is "DbUser" EF will look for "DbUserId" or "DbUser_Id", not "UserId" so you need to explicitly set these mappings. (Annotations or fluent config)
You will need to be very careful with tracking references to these entities as the NoAction
delete behavior will result in exceptions being raised if EF interprets your code as removing entities or setting navigation properties to #null. Often errors occurring when updating or creating rows involving navigation properties are due to bad assumptions around tracked/untracked references rather than mapping.
本文标签: cHow to set up a cyclic connection in EF CoreStack Overflow
版权声明:本文标题:c# - How to set up a cyclic connection in EF Core? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743998757a2573472.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
CREATE TABLE
statements) to your question to make it more clear what exact columns you have (and what the foreign keys are). – Progman Commented Mar 30 at 6:57public ICollection<DbWork> Works { get; set; } = new List<DbWork>();
onDbUser
doesn't make a huge amount of sense. Just keepLikes
. – Charlieface Commented Mar 30 at 9:52.HasForeignKey
on some navigations. But I can't be certain without seeing how it fails. – Jeremy Lakeman Commented Mar 31 at 0:58