У меня есть много разных отношений, кратко
Cases -----< CaseSubjectRelationships >------ CaseSubjects
Более полно:
Случаи ( ID, CaseTypeID,.......)
CaseSubjects ( ID, DisplayName, CRMSPIN)
CaseSubjectsRelationships ( CaseID, SubjectID, PrimarySubject, RelationToCase,...)
В моей таблице ссылок "многие-ко-многим" есть дополнительные свойства, относящиеся к предметной ассоциации с конкретным случаем - например, дата начала, дата окончания, отношение свободного текста к случаю (наблюдатель, создатель и т.д.)
Создана модель данных Entity Framework - версия ASP.NET 4.0
У меня есть служба WCF с методом CreateNewCase
, который принимает в качестве своего параметра объект Case
(объект, созданный Entity Framework) - его задача состоит в том, чтобы сохранить регистр в базе данных.
Служба WCF вызывается сторонним инструментом. Здесь отправлен SOAP:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<CreateNewCase xmlns="http://tempuri.org/">
<c xmlns:a="http://schemas.datacontract.org/2004/07/CAMSModel">
<a:CaseSubjectsRelationships>
<a:CaseSubjectsRelationship>
<a:CaseSubject>
<a:CRMSPIN>601</a:CRMSPIN>
<a:DisplayName>Fred Flintstone</a:DisplayName>
</a:CaseSubject>
<a:PrimarySubject>true</a:PrimarySubject>
<a:RelationToCase>Interested</a:RelationToCase>
<a:StartDate>2011-07-12T00:00:00</a:StartDate>
</a:CaseSubjectsRelationship>
<a:CaseSubjectsRelationship>
<a:CaseSubject>
<a:CRMSPIN>602</a:CRMSPIN>
<a:DisplayName>Barney Rubble</a:DisplayName>
</a:CaseSubject>
<a:RelationToCase>Observer</a:RelationToCase>
<a:StartDate>2011-07-12T00:00:00</a:StartDate>
</a:CaseSubjectsRelationship>
</a:CaseSubjectsRelationships>
<a:CaseType>
<a:Identifier>Change of Occupier</a:Identifier>
</a:CaseType>
<a:Description>Case description</a:Description>
<a:Priority>5</a:Priority>
<a:QueueIdentifier>Queue One</a:QueueIdentifier>
<a:Title>Case title</a:Title>
</c>
</CreateNewCase>
</s:Body>
</s:Envelope>
Двигатель WCF десериализует это в объект Case для меня правильно, и когда я смотрю в отладчике, все настроено правильно.
Что я хочу сделать, только создайте новый CaseSubject
, если в базе данных уже нет записи с указанным CRMSPIN
(CRMSPIN является ссылочным номером из центральной клиентской базы данных)
Итак, в приведенном ниже примере я хочу посмотреть, есть ли у меня уже запись в CaseSubjects
для кого-то с CRMSPIN 601, и если я это сделаю, я не хочу создавать другую (дублирующую) запись, но вместо этого новый случай ссылается на существующий предмет (хотя для новой строки потребуется, очевидно, необходимость создания в CaseSubjectsRelationships с конкретной дополнительной информацией, такой как отношения и т.д.)
Вот код .NET, который я пытался сделать.
Public Class CamsService
Implements ICamsService
Public Function CreateNewCase(c As CAMSModel.Case) As String Implements ICamsService.CreateNewCase
Using ctx As New CAMSEntities
' Find the case type '
Dim ct = ctx.CaseTypes.SingleOrDefault(Function(x) x.Identifier.ToUpper = c.CaseType.Identifier.ToUpper)
' Give an error if no such case type '
If ct Is Nothing Then
Throw New CaseTypeInvalidException(String.Format("The case type {0} is not valid.", c.CaseType.Identifier.ToString))
End If
' Set the case type based on that found in database: '
c.CaseType = ct
For Each csr In c.CaseSubjectsRelationships
Dim spin As String = csr.CaseSubject.CRMSPIN
Dim s As CaseSubject = ctx.CaseSubjects.SingleOrDefault(Function(x) x.CRMSPIN = spin)
If Not s Is Nothing Then
' The subject has been found based on CRMSPIN so set the subject in the relationship '
csr.CaseSubject = s
End If
Next
c.CreationChannel = "Web service"
c.CreationDate = Now.Date
' Save it '
ctx.AddToCases(c)
ctx.SaveChanges()
End Using
' Return the case reference '
Return c.ID.ToString
End Function
End Class
Как вы можете видеть, вместо цикла For Each
я пытаюсь получить объект на основе CRMSPIN, и если я что-то получу, я обновляю объект CaseSubject. (Я также попробовал csr.SubjectID = s.ID
вместо установки всей сущности, а также попытался установить их оба!).
Однако, даже если положить точку останова на строку ctx.SaveChanges()
и посмотреть, как настраиваются объекты и видеть в отладчике, что она выглядит нормально, она всегда создает новую строку в таблице CaseSubjects.
Я вижу, что в принципе это должно сработать - вы увидите, что я сделал то же самое для Case Type - я выбрал идентификатор, отправленный в XML, нашел объект с этим идентификатором через контекст, а затем изменил случай .CaseType
сущности, которую я нашел. Когда он сохраняет, он работает отлично и, как ожидалось, и без дублированных строк.
У меня просто возникают проблемы с попыткой применить одну и ту же теорию к одной стороне отношения "многие ко многим".
Вот некоторые (надеюсь, релевантные) выдержки из .edmx
<EntitySet Name="Cases" EntityType="CAMSModel.Store.Cases" store:Type="Tables" Schema="dbo" />
<EntitySet Name="CaseSubjects" EntityType="CAMSModel.Store.CaseSubjects" store:Type="Tables" Schema="dbo" />
<EntitySet Name="CaseSubjectsRelationships" EntityType="CAMSModel.Store.CaseSubjectsRelationships" store:Type="Tables" Schema="dbo" />
<AssociationSet Name="FK_CaseSubjectsRelationships_Cases" Association="CAMSModel.Store.FK_CaseSubjectsRelationships_Cases">
<End Role="Cases" EntitySet="Cases" />
<End Role="CaseSubjectsRelationships" EntitySet="CaseSubjectsRelationships" />
</AssociationSet>
<AssociationSet Name="FK_CaseSubjectsRelationships_CaseSubjects" Association="CAMSModel.Store.FK_CaseSubjectsRelationships_CaseSubjects">
<End Role="CaseSubjects" EntitySet="CaseSubjects" />
<End Role="CaseSubjectsRelationships" EntitySet="CaseSubjectsRelationships" />
</AssociationSet>
РЕДАКТ.: Устройства свойств для свойства CaseSubject
объекта CaseSubjectsRelationships
:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
<XmlIgnoreAttribute()>
<SoapIgnoreAttribute()>
<DataMemberAttribute()>
<EdmRelationshipNavigationPropertyAttribute("CAMSModel", "FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject")>
Public Property CaseSubject() As CaseSubject
Get
Return CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of CaseSubject)("CAMSModel.FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject").Value
End Get
Set
CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of CaseSubject)("CAMSModel.FK_CaseSubjectsRelationships_CaseSubjects", "CaseSubject").Value = value
End Set
End Property