我的情况我想存储一个地址,但必须是可选的。
我的映射看起来像这样:
map.OwnsOne(x => x.Address, cb => cb.OwnsOne(l => l.Location));
但是当我将DbContext与Address as为空时,我得到了这个错误:
InvalidOperationException:'会员'的实体正在分享这张桌子 '成员'使用' Member.Address#StreetAddress',但没有实体 此类型具有相同的键值' Id:-2147480644'那已经 标记为'已添加'。
然后我从构造函数中实例化了Address和Location,现在我可以保存实体了。但是当再次获取数据时,我还获得了一个实例化的地址,其中我真的想要一个空值。
是否无法制作可归类的拥有类型?
答案 0 :(得分:5)
是否无法创建可为空的拥有类型?
从EF Core 3开始,?现在可以了。
所有依赖项现在都是可选的。 (在预览版4中发货): Source
static void Main(string[] args)
{
using (var context = new OwnedEntityContext())
{
context.Add(new DetailedOrder
{
Status = OrderStatus.Pending,
OrderDetails = new OrderDetails
{
ShippingAddress = new StreetAddress
{
City = "London",
Street = "221 B Baker St"
}
//testing 3.0: "Yes, all dependents are now optional"
//reference: https://github.com/aspnet/EntityFrameworkCore/issues/9005#issuecomment-477741082
//NULL Owned Type Testing
//BillingAddress = new StreetAddress
//{
// City = "New York",
// Street = "11 Wall Street"
//}
}
});
context.SaveChanges();
}
//read test
using (var context = new OwnedEntityContext())
{
#region DetailedOrderQuery
var order = context.DetailedOrders.First(o => o.Status == OrderStatus.Pending);
Console.Write("NULL Owned Type Test, Is Billing Address NULL?");
//PRINTS FALSE
Console.WriteLine($"{order.OrderDetails.BillingAddress == null}");
#endregion
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region OwnsOneNested
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
od.OwnsOne(c => c.BillingAddress);
od.OwnsOne(c => c.ShippingAddress);
});
#endregion
#region OwnsOneTable
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
od.OwnsOne(c => c.BillingAddress);
od.OwnsOne(c => c.ShippingAddress);
od.ToTable("OrderDetails");
//Exception message:Microsoft.Data.SqlClient.SqlException:
//'Cascading foreign key 'FK_OrderDetails_DetailedOrders_OrderId' cannot
//be created where the referencing column 'OrderDetails.OrderId' is an identity column.
//Could not create constraint or index. See previous errors.'
//3.0 bug: https://github.com/aspnet/EntityFrameworkCore/issues/17448#issuecomment-525444101
//fixed in 3.1: https://github.com/aspnet/EntityFrameworkCore/pull/17458
od.Property("OrderId")
.ValueGeneratedNever();
});
#endregion
}
答案 1 :(得分:3)
拥有类型的一个限制是不支持可选(即可为空)。 我建议你按照这个帖子。 https://github.com/aspnet/EntityFramework.Docs/issues/466
在我的解决方案中,我使用空对象方法并使用IsEmpty方法来了解地址是否为空而不是询问地址是否为空。我希望这种方法可以帮助你。
public sealed class Address : ValueObject<Address>
{
public string StreetAddress1 { get; private set; }
public string StreetAddress2 { get; private set; }
public string City { get; private set; }
public string State { get; private set; }
public string ZipCode { get; private set; }
public string Country { get; private set; }
private Address() { }
public Address(string streetAddress1, string city, string state, string zipcode, string country)
{
StreetAddress1 = streetAddress1;
City = city;
State = state;
ZipCode = zipcode;
Country = country;
}
public Address(string streetAddress1, string streetAddress2, string city, string state, string zipcode, string country)
: this(streetAddress1, city, state, zipcode, country)
{
StreetAddress2 = streetAddress2;
}
public static Address Empty()
{
return new Address("", "", "", "", "");
}
public bool IsEmpty()
{
if (string.IsNullOrEmpty(StreetAddress1)
&& string.IsNullOrEmpty(City)
&& string.IsNullOrEmpty(State)
&& string.IsNullOrEmpty(ZipCode)
&& string.IsNullOrEmpty(Country))
{
return true;
}
else
{
return false;
}
}
}
public class Firm : AggregateRoot<Guid>
{
public string Name { get; private set; }
public Address Address { get; private set; }
private Firm() { }
public Firm(string name)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentException();
Id = Guid.NewGuid();
Name = name;
Address = Address.Empty();
}
}
答案 2 :(得分:2)
实体框架document指出
除非拥有实体类型的引用导航,否则它们不能为空 明确地映射到所有者以外的单独表
因此,实际上,您的问题有解决方案。您需要将自己的实体映射到单独的表,而不是将其与所有者放在同一表中。
map.OwnsOne(x => x.Address, cb => cb.OwnsOne(l => l.Location, l=> l.ToTable("Locations")));
通过将位置实体映射到名为 Locations 的单独表中,拥有的实体将变为可空。
答案 3 :(得分:1)
在此处查看:https://msdn.microsoft.com/en-us/magazine/mt846463.aspx,然后向下滚动到“临时工作区以允许空值对象”。
可以在此处找到一个简短的示例:https://entityframeworkcore.com/knowledge-base/48063630/nullable-owned-types-in-ef-core
如果没有这种解决方法,我很高兴能够做到这一点,但是我不认为这是可能的。