简体   繁体   中英

How can I remove an optional relationship using Automapper in Entity Framework Core

I have the following Entities and DTOs:

public class Endpoint
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Port { get; set; }
    public bool IsHttps { get; set; }

    public int? CertificateID { get; set; }
    public Certificate? Certificate { get; set; }
}

public class Certificate
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string FileName { get; set; }
}

public class EndpointDTO
{
    public int Port { get; set; }
    public bool IsHttps { get; set; }
    public string? CertificateName { get; set; }
}

Because an Endpoint could be using HTTP, the Certificate is optional. The Certificate.Name property has a unique index. I am now trying to make the scaffolded CRUD Razor Pages work with my EndpointDTO using Automapper. The Delete and Details page work as expected. For the create Page, my implementation looks like this:

[BindProperty]
public EndpointDTO Endpoint { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    if (!this.ModelState.IsValid)
    {
        return this.Page();
    }

    var endpoint = this.mapper.Map<Endpoint>(this.Endpoint);

    endpoint.Certificate = this.context.Certificates
        .FirstOrDefault(c => c.Name.Equals(this.Endpoint.CertificateName));
    this.context.Endpoints.Add(endpoint);
    await this.context.SaveChangesAsync();

    return this.RedirectToPage("./Index");
}

This works too, but it feels wrong that I have to manually select the Certificate. The Edit Page does not work. When I try to "unselect" a certificate (pass null as the EndpointDTO.CertificateName ), the mapper creates a Certificate with default (null) values. Here is my implementation:

public async Task<IActionResult> OnPostAsync()
{
    if (!this.ModelState.IsValid)
    {
        return this.Page();
    }

    var original = this.context.Endpoints
        .Include(e => e.Certificate)
        .FirstOrDefault(e => e.Port == this.Endpoint.Port);
    original!.Certificate = this.context.Certificates
        .FirstOrDefault(c => c.Name.Equals(this.Endpoint.CertificateName));
    this.mapper.Map(this.Endpoint, original);

    await this.context.SaveChangesAsync();

    return this.RedirectToPage("./Index");
}

The error that i receive is

SQLite Error 19: 'NOT NULL constraint failed: Certificates.FileName'

Is this an Automapper configuration issue? I currently use ...CreateMap<Endpoint, EndpointDTO>().ReverseMap(); .

Or do I need to manually catch the case, where a Certificate was "unselected"? How would I go about doing that cleanly?

Because your map is not know your entity property. Reason of the they have different property name. You should set manual. Look ForMember in AutoMapper

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM