我在旧数据库系统上使用linq2sql。在这个系统中有三个表,Invoices,Users和SignupUsers。 Invoices表有一个UID字段,通常引用Users表上的UID键。但是,它还有一个IsSignup位字段,指示UID字段应该引用SignupUsers表上的UID键。
我并不关心与SignupUsers表的关系,但我们确实遇到一个问题,即在使用linq2sql实体时很容易忘记检查“IsSignup”值。我想根据IsSignup位字段使实体中的Invoices-> Users关系成为可能。
我尝试了几种方法。首先我尝试设置OnLoaded:
public partial class Invoice
{
partial void OnLoaded()
{
if (IsSignup)
{
InvoiceUser = null;
}
}
}
这会失败,因为它会在将发票保存回来时尝试将UID字段实际设置为null - 这是我们无法做到的。
我使用DataLoadOptions进行了调查,但无法找到使其工作的方法。
我可以更改InvoiceUsers属性getter,但每次dbml更改时都会被覆盖。
我在这里运气不好吗?
答案 0 :(得分:0)
我会在这里提出解决方案,但仍希望有人能提出更好的解决方案。
我正在使用LINQ to SQL templates for T4来生成代码。我进入了.tt文件,找到了这个特定的.dbml文件,找到了生成关系属性的部分。然后我攻击了一个“if”语句,如果它应用于这个特定的关系,它就修改了属性:
<#=code.Format(association.MemberAttributes)#><#=association.Type.Name#> <#=association.Member#>
{
get {
<#if(association.Name == "InvoiceUser_Invoice"){#>
//HACK IN THE .TT FILE TO ALWAYS INCLUDE THIS CONDITIONAL RELATIONSHIP
if(IsSignup){return null;}
<#}#>
<#if (needsSerializationFlag && serialization) {#>
if (serializing && !<#=association.Storage#>.HasLoadedOrAssignedValue) {
return null;
}
<#}#>
return <#=association.Storage#>.Entity;
}
这使得该特定属性的生成代码符合要求:
[Association(Name=@"InvoiceUser_Invoice", Storage=@"_InvoiceUser", ThisKey=@"UID", OtherKey=@"UID", IsForeignKey=true)]
public InvoiceUser InvoiceUser
{
get {
//HACK IN THE .TT FILE TO ALWAYS INCLUDE THIS CONDITIONAL RELATIONSHIP
if(IsSignup){return null;}
return _InvoiceUser.Entity;
}
set {
InvoiceUser previousValue = _InvoiceUser.Entity;
if ((previousValue != value) || (!_InvoiceUser.HasLoadedOrAssignedValue)) {
SendPropertyChanging();
if (previousValue != null) {
_InvoiceUser.Entity = null;
previousValue.Invoices.Remove(this);
}
_InvoiceUser.Entity = value;
if (value != null) {
value.Invoices.Add(this);
_UID = value.UID;
}
else {
_UID = default(int);
}
SendPropertyChanged("InvoiceUser");
}
}
}
所以仍然是一个令人讨厌的黑客攻击,但它至少可以防止.dbml文件的更改删除所需的条件关系。