我正在尝试为联结表OwnerCows.dbo简化EF模型。 有一个带有ID的Cow类,一个带有ID的Owner类,我想在一个只有OwnerCowId,CowId(FK)和OwnerId(FK)的OwnerCows表中引用它们。
我得到的错误是: 无法在“ Owner.OwnerCows”和“ OwnerCow.Owner”之间创建关系,因为“ Owner.CowOwners”和“ OwnerCow.Owner”之间已经存在关系。导航属性只能参与单个关系。
这是否意味着我有一个循环引用?我该怎么解决?
Owner.cs:
public class Owner : EntityBase<Guid>
{
public string Name { get; set; }
[NotMapped]
public ICollection<Cow> Cows { get; set; }
= new List<Cow>();
public virtual List<OwnerCow> CowOwners { get; set; }
public Cow Cow { get; set; }
}
Cow.cs:
public class Cow : EntityBase<Guid>
{
[MaxLength(50)]
public string Name { get; set; }
public string Breed { get; set; }
public string Color { get; set; }
public ICollection<Entities.Weight> Weights { get; set; }
= new List<Weight>();
public ICollection<Vaccination> Vaccinations { get; set; }
= new List<Vaccination>();
[NotMapped]
public ICollection<Owner> CowOwners { get; set; }
= new List<Owner>();
public List<OwnerCow> OwnerCows { get; set; }
}
OwnerCows.cs:
public class OwnerCow
{
public Guid OwnerCowId { get; set; }
public Cow Cow { get; set; }
public Guid CowId { get; set; }
public Owner Owner { get; set; }
public Guid OwnerId { get; set; }
}
上下文类:
public class DogFaceContext : DbContext
{
public DogFaceContext()
{
}
public DogFaceContext(DbContextOptions<DogFaceContext> options)
: base(options)
{
Database.Migrate();
}
//Entity Tables
public virtual DbSet<Owner> Owners { get; set; }
public virtual DbSet<Cow> Cows { get; set; }
public virtual DbSet<Vaccination> Vaccination { get; set; }
public virtual DbSet<Weight> Weight { get; set; }
//Junction Tables
public virtual DbSet<OwnerCow> OwnerCows { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Cow>().HasMany(x => x.CowOwners).WithOne(x => x.Cow);
builder.Entity<Owner>().HasMany(u => u.CowOwners).WithOne(X => X.Owner);
builder.Entity("DogFace.API.Entities.OwnerCow", b =>
{
b.HasOne("DogFace.API.Entities.Cow", "Cow")
.WithMany("OwnerCows")
.HasForeignKey("CowId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("DogFace.API.Entities.Owner", "Owner")
.WithMany("OwnerCows")
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Restrict);
});
}
}
我可以使它与这种设计一起使用吗? EFCore是否可以?还有其他建议吗?谢谢!
答案 0 :(得分:1)
修复上下文生成器:
#pragma mark - private
- (void)createWithName:(NSString *)name andLogo:(UIImage * _Nullable)logo {
self.opaque = NO;
self.alpha = 0.9;
self.backgroundColor = COLOR(0xfcfcfc);
// if (@available(iOS 13.0, *)) {
// self.backgroundColor = UIColor.secondarySystemBackgroundColor;
// }
CGSize labelSize = CGSizeZero;
if (logoView == nil) {
if (logo != nil) {
logoView = [[UIImageView alloc] initWithImage:logo];
[self addSubview:logoView];
} else {
NSString *imagePath = [XXUtility pathForResourceNamed:@"Logo" withExtension:@"png"];
UIImage *imageToAdd = [[UIImage alloc] initWithContentsOfFile:imagePath];
logoView = [[UIImageView alloc] initWithImage:imageToAdd];
[self addSubview:logoView];
}
}
if (textLabel == nil) {
textLabel = [[UILabel alloc] init];
NSString * labelString = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"welcom banner", @"userInterface", [XXUtility bundleForStrings], @"Dear %@, welcome into game", @"user welcome banner text"), name];
labelSize = [labelString sizeWithAttributes:@{NSFontAttributeName : textLabel.font}];
textLabel.text = labelString;
[self addSubview:textLabel];
}
NSLog(@"XXUserWelcomeBanner Label size is %f x %f", labelSize.height, labelSize.width);
[self bannerSizeWithLabelSize:labelSize];
CGFloat bannerHeight = self.frame.size.height;
CGFloat bannerWidth = self.frame.size.width;
CGFloat logoHeight = bannerHeight * 0.45;
CGFloat logoWidth = logoHeight;
CGFloat logoXPos = (bannerWidth - logoWidth - labelSize.width) / 2;
CGFloat logoYPos = (bannerHeight - logoHeight) / 2;
CGFloat labelHeight = labelSize.height;
CGFloat labelWidth = labelSize.width;
CGFloat labelXPos = logoXPos + logoWidth + 5;
CGFloat labelYPos = (bannerHeight - labelHeight) / 2;
logoView.frame = CGRectMake(logoXPos, logoYPos, logoWidth, logoHeight);
textLabel.frame = CGRectMake(labelXPos, labelYPos, labelWidth, labelHeight);
[self bannerShow];
}
- (void)bannerSizeWithLabelSize:(CGSize)lSize {
_width = 40 + lSize.width + 5;
CGFloat height = 40;
CGFloat xPosition = ScreenWidth * 1/2 - _width * 1/2;
CGFloat yPosition = - height;
self.frame = CGRectMake(xPosition, yPosition, _width, height);
}
- (void)bannerShow {
UIViewController *vc;
if ([TOP_VIEWCONTROLLER respondsToSelector:@selector(topViewController)]) {
vc = [TOP_VIEWCONTROLLER topViewController];
} else {
vc = TOP_VIEWCONTROLLER;
}
[vc.view addSubview:self];
[UIView animateWithDuration:0.6 delay:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
CGFloat height = 40;
CGFloat xPos = ScreenWidth * 1/2 - self->_width * 1/2;
CGFloat yPos = height * 1/3 + KiPhoneXSafeAreaDValue;
self.frame = CGRectMake(xPos, yPos, self->_width, height);
} completion:^(BOOL finished) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.6 delay:0.2 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGFloat height = 40;
CGFloat xPosition = ScreenWidth * 1/2 - self->_width * 1/2;
CGFloat yPosition = - height;
self.frame = CGRectMake(xPosition, yPosition, self->_width, height);
} completion:^(BOOL finished) {
[self bannerDestroy];
self.alpha = 0;
}];
});
}];
}
- (void)bannerDestroy {
[logoView removeFromSuperview];
[textLabel removeFromSuperview];
logoView = nil;
textLabel = nil;
[self removeFromSuperview];
}
- (void)dealloc
{
//
NSLog(@"uiview dealloc");
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
...或修复类中的属性名称:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Cow>().HasMany(x => x.CowOwners).WithOne(x => x.Cow);
builder.Entity<Owner>().HasMany(u => u.Cows).WithOne(X => X.Owner); // Cows instead of CowOwners
builder.Entity("DogFace.API.Entities.OwnerCow", b =>
{
b.HasOne("DogFace.API.Entities.Cow", "Cow")
.WithMany("OwnerCows")
.HasForeignKey("CowId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("DogFace.API.Entities.Owner", "Owner")
.WithMany("CowOwners") // CowOwners instead of OwnerCows
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Restrict);
});
}
但是请不要忘记更改具有固定属性名称的dbcontext构建器。
答案 1 :(得分:1)
您的模型非常复杂并且具有一些不必要的关系,例如Owner.Cows,因为您决定配置多对多关系。您可以使用
来获得Owner's cowsvar owner = new Owner();
List<Cow> cows = owner.OwnerCows.Where(oc => oc.OwnerId == owner.Id)
.Select(oc => oc.Cow)
.ToList();
1。要在OwnerCows中拥有OwnerCowId,CowId(FK)和OwnerId(FK),请参阅我的以下配置:
public class Owner : EntityBase<Guid>
{
public string Name { get; set; }
public virtual List<OwnerCow> OwnerCows { get; set; }
}
public class Cow : EntityBase<Guid>
{
[MaxLength(50)]
public string Name { get; set; }
public string Breed { get; set; }
public string Color { get; set; }
public ICollection<Entities.Weight> Weights { get; set; } = new List<Weight>();
public ICollection<Vaccination> Vaccinations { get; set; }= new List<Vaccination>();
public List<OwnerCow> OwnerCows { get; set; }
}
public class OwnerCow
{
[Key]
public Guid OwnerCowId { get; set; }
public Cow Cow { get; set; }
public Guid CowId { get; set; }
public Owner Owner { get; set; }
public Guid OwnerId { get; set; }
}
DbContext:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<OwnerCow>()
.HasOne(oc => oc.Cow)
.WithMany(c => c.OwnerCows)
.HasForeignKey(oc => oc.CowId);
builder.Entity<OwnerCow>()
.HasOne(oc => oc.Owner)
.WithMany(o => o.OwnerCows)
.HasForeignKey(oc => oc.OwnerId);
}
}
在这种情况下,您的OwnerCowId
ID是OwnerCows
表的主键,这是不合理的,它可能与OwnerCows的CowId,OwnerId记录相同。
2。通常,联接表的主键是一个包含两个外键值的复合键,我建议您可以对OwnerCow
使用复合键:
public class OwnerCow
{
public Cow Cow { get; set; }
public Guid CowId { get; set; }
public Owner Owner { get; set; }
public Guid OwnerId { get; set; }
}
DbContext:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<OwnerCow>()
.HasKey(oc => new { oc.OwnerId, oc.CowId });
builder.Entity<OwnerCow>()
.HasOne(oc => oc.Cow)
.WithMany(c => c.OwnerCows)
.HasForeignKey(oc => oc.CowId);
builder.Entity<OwnerCow>()
.HasOne(oc => oc.Owner)
.WithMany(o => o.OwnerCows)
.HasForeignKey(oc => oc.OwnerId);
}
}
请参阅https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration