У меня есть отношения многие ко многим, кратко
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 вызывается сторонним инструментом. Вот мыло отправлено:
<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