Pergunta

I have this class structure:

public class Activity {

    [Key]
    public long ActivityId { get; set; }
    public string ActivityName { get; set; }

    public virtual HashSet<ActivityLogMessage> ActivityLogMessages { get; set; }
    public virtual HashSet<FileImportLogMessage> FileImportLogMessages { get; set; }
    public virtual HashSet<RowImportLogMessage> RowImportLogMessages { get; set; }

}

public abstract class LogMessage
{
    [Required]
    public string Message { get; set; }
    public DateTimeOffset CreateDate { get; set; }

    [Required]
    public long ActivityId { get; set; }
    public virtual Activity Activity { get; set; }
}

public class ActivityLogMessage : LogMessage
{
    public long ActivityLogMessageId { get; set; }
}

public class FileImportLogMessage : ActivityLogMessage
{
    public long? StageFileId { get; set; }
}

public class RowImportLogMessage : FileImportLogMessage
{
    public long? StageFileRowId { get; set; }
}

Which gives me this, model

EF5 Entity Model

Each Message (Activity, File or Row) must have be associated with an Activity. Why does the 2nd and 3rd level not have the same cardinality as ActivityLogMessage ? My attempts at describing the foreign key relationship (fluent via modelbuilder) have also failed.

This is really an academic exercise for me to really understand how EF is mapping to relational, and this confuses me.

Regards, Richard

Foi útil?

Solução

EF infers a pair of navigation properties Activity.ActivityLogMessages and ActivityLogMessage.Activity with a foreign key property ActivityLogMessage.ActivityId which is not nullable, hence the relationships is defined as required.

The other two relationships are infered from the collections Activity.FileImportLogMessages and Activity.RowImportLogMessages. They neither have an inverse navigation property on the other side nor a foreign key property which will - by default - lead to optional relationships.

You possibly expect that LogMessage.Activity and LogMessage.ActivityId is used as inverse property for all three collections. But it does not work this way. EF cannot use the same navigation property in multiple relationships. Also your current model means that RowImportLogMessage for example has three relationships to Activity, not only one.

I believe you would be closer to what you want if you remove the collections:

public virtual HashSet<FileImportLogMessage> FileImportLogMessages { get; set; }
public virtual HashSet<RowImportLogMessage> RowImportLogMessages { get; set; }

You can still filter the remaining ActivityLogMessages by the derived types (for example in not mapped properties that have only a getter):

var fileImportLogMessages = ActivityLogMessages.OfType<FileImportLogMessage>();
// fileImportLogMessages will also contain entities of type RowImportLogMessage

var rowImportLogMessage = ActivityLogMessages.OfType<RowImportLogMessage>();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top