One to One or Zero Ratio with OneWay CascadeOnDelete

I have an object that includes many different documents with fuzzy relationships to any objects in my database.

public class Document : BaseEntity
{

    public string Filename { get; set; }

    public string MIMEType { get; set; }
    public int? Length { get; set; }

    public byte[] Content { get; set; }

}

      

and codefirst-mapping:

    public DocumentConfiguration()
    {
        Property(x => x.Filename).HasMaxLength(300).IsRequired();
        Property(x => x.MIMEType).HasMaxLength(300).IsRequired();
        Property(x => x.Length).IsOptional();
        Property(x => x.Content).IsOptional().HasColumnType("varbinary(max)");


        ToTable("Document"); 
    }

      

Now I want an optional relation to the document table in my targeting like this:

public class Address : BaseEntity
{

    public string Name1 { get; set; }
    public string Name2 { get; set; }
    public string Additional { get; set; }


    public string Street { get; set; }
    public string HousNr { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }

    public virtual Document Image { get; set; }

}

      

with the following display:

    public AddressConfiguration()
    {

        Property(x => x.Name1).IsRequired().HasMaxLength(250);
        Property(x => x.Name2).HasMaxLength(250);
        Property(x => x.Additional).HasMaxLength(250);


        Property(x => x.Street).HasMaxLength(250);
        Property(x => x.HousNr).HasMaxLength(10);
        Property(x => x.ZipCode).HasMaxLength(10);
        Property(x => x.City).HasMaxLength(100);


        HasOptional(x => x.Image)
            .WithOptionalDependent()
            .Map(map => map.MapKey("ImageId")).WillCascadeOnDelete();


        ToTable("Address");

    }

      

But it removes the associated address when I delete the image in the document table.

I would like OneWay-Deletation from address to document, but not from document to address ...?

How can I implement this?

thank.

+3


source to share


2 answers


The reason it cascades from document to address is because you used the WithOptionalDependent method . From the documentation:

Configures the relationship as optional: optionally without a navigation property on the other side of the relationship. The custom object type will be dependent and contain a foreign key for the principal. The type of entity in which the relationship will be the main relationship.

Consider this line of code in the AddressConfiguration method:

HasOptional(x => x.Image)         // The entity type being configured is Address
   .WithOptionalDependent()...   // The entity type that the relationship targets
                                //  is Document (x.Image)

      

This means that you are effectively specifying the address as dependent and Document as the primary in this association, hence the cascading behavior.

But wait, there is another story! You can create a one-to-one association in two ways. The first is the Shared Primary Key Association or One-to-One Private Key Association. You can learn more about them from here and here . It sounds like you want to map your association with a foreign key (Individual Association with One Person). If so, you should notice that the dependent object will always have a foreign key, which means, in your case, the Document object will have an AddressId referenced by the AddressId on Address object (you did the opposite wrong.).



With that said, your object model and loose API should look like this:

public class Address 
{
    public int AddressId { get; set; }
    public virtual Document Image { get; set; }
}

public class Document 
{
    public int DocumentId { get; set; }
}

class Context : DbContext
{
    public DbSet<Address> Addresses { get; set; }
    public DbSet<Document> Documents { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Address>()  // The entity being configured is Address
                    .HasOptional(x => x.Image)  
                    .WithOptionalPrincipal()
                    .Map(map => map.MapKey("AddressId"))
                    .WillCascadeOnDelete();
    }
}

      

Basically WithOptionalPrincipal is the method you should be using:

Configures the relationship as optional: optionally without a navigation property on the other side of the relationship. The type of object to be configured will be the main one in the relation. The type of object in which the target relationship will be dependent and contain a foreign key for the principal.


As a result, cascading deletion is properly incorporated from the address into the document.

+5


source


Try to remove OneToManyCascadeDeleteConvention: modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention >();



0


source







All Articles