简体   繁体   中英

My EF6 code-first model seems very inefficient but I don't know how to improve it. Am I missing something?

I am currently modeling two classes in asp.net using entity framework 6 using a code-first approach. A user can create a Widget, where a Widget has a collection of up to five WidgetOptions. The options are primarily strings but there is metadata associated with them that other users need to interact with (hence why they are not just a collection of strings). Currently, my classes look something like this:

Widget {
    public string Name {g;s;}
    ... //more fields
    public string ICollection<WidgetOption> Options {g;s;}
}

WidgetOption {
    public string Option {g;s;}
    ... //more fields
}

This obviously seems simple enough, but here are my thoughts. So currently, when a user creates a widget in the UI, the controller is creating a list of WidgetOptions from the strings that the user enters, assigning the WidgetOptions to the Widget, then saving to the database context. As in:

Create(WidgetFormViewModel vm) {
    var options = vm.WidgetOptions.Select(wo => new WidgetOption(wo)).ToList();
    var widget= new Widget { 
        Options = options,
        // ... other fields from vm
    };
    _context.Widgets.Add(widget);
    _context.SaveChanges();
    return RedirectToAction("Index", "Home");
}

The problem is that many users are likely to repeat WidgetOption strings. For instance, a lot of users might name an option "red" to make the Widget red (while that may seem weird, the actual case makes a lot more sense). Entity Framework is currently modeling the classes as having no columns in Widget that reference WidgetOption, and the WidgetOption having Id, Option, and Widget_Id columns.

So if two users make a Widget with a "red" WidgetOption, there will be two rows created in the WidgetOption table. Each with a unique Id and each with the corresponding Widget_Id. This seems really inefficient in terms of space, but I could be wrong (in that it's not as much space as I think is being wasted). I guess, even if I had a separate table with only unique WidgetOption strings, I would still need a relationship table that connected a Widget to Many WidgetOptions. That could be more efficient than the current model if the WidgetOption_Id in the relationship table was much smaller than the string itself, right? Except then I would have to search for each string that the user enters to see if it had been created. So I'd be sacrificing speed for storage.

I'm not sure if I'm overthinking this or not, but I just feel weird having a table where WidgetOptions are repeated. If there were only a few unique option strings, a many to many relationship makes more sense, while the current model would make sense if every option string was unique. It seems like the right choice can only be solved by figuring out which end of this scale occurs in practice.

Rewrite your Widget and WidgetOption entities this way:

Widget {
    public string Name {g;s;}
    ... //more fields
    public virtual ICollection<WidgetOption> WidgetOptions {g;s;}
}

WidgetOption {
    public string Option {g;s;}
    ... //more fields
    public virtual ICollection<Widget> Widgets {g;s;}
}

It would tell Entity Framework to define many-to-many relationship between Widget and WidgetOption . I believe this should take care of the issue that has been bothering you. Though, it might require a little change in code to add WidgetOptions .

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