How to model a collection of items where one of them is the active item?

kashmoneymillionaire

I have a situation where an entity has a list of children that are inactive. Additionally, they have another "current/active" sub entity of the same type.

The following would be the ideal modeling, but I cannot figure out how to this with Entity Framework Core:

public class Customer 
{
    public Application CurrentApplication { get; set; }
    public List<Application> PastApplications { get; set; }
}

public class Application
{
    public bool IsCurrent { get; set; }
    public Customer Customer { get; set; }
}

In the past, I've typically modeled it as so:

public class Customer
{
    public Application CurrentApplication => AllApplications.Single(a => a.IsCurrent);
    public List<Application> PastApplications => AllApplications.Where(a => !a.IsCurrent);  
    public List<Application> AllApplications { get; set; }   
}

public class Application
{
    public bool IsCurrent { get; set; }
    public Customer Customer { get; set; }
}

However, I feel that this could lead to the possibility of another Application incorrectly being set as IsCurrent, thus breaking the .Single().

What's the suggested way to accomplish this from a DDD perspective? If that doesn't match up with what EF Core can do, what is a good practical suggestion?

Adam Simon

I don't think that this is a DDD problem, rather a how to design a relational DB model and how to use EF Core question.

First you need to decide what is the relationship between Customers and Applications:

  • One-to-Many, that is, a Customer may have zero or more Applications, but an Application belongs to exactly one Customer. This scenerio is also called a master-detail relationship. The entity on the Many side (Application in this case) stores a reference (called a foreign key) to its owner (Customer).
  • Many-to-Many, that is, a Customer may have zero or more Applications, but an Application may belong to zero or more Customers, as well. This scenario is modelled using an extra "join" table (usually named something like CustomerApplication) so the problem is resolved to two One-to-May relationships in the end.

If there is only one active Application at a given time (per customer), the active application can be modelled using a One-to-One (Zero-to-One, to be precise) relationship between Customer and Application (with a foreign key on Customer's side). It can also be modelled using a flag field on Application as you tried but that's not as error-proof as a foreign key (but may have better performance, though).

The code you posted resembles rather a One-to-Many scenario, so I show an example for that case. Understanding the following, you can easily change it Many-to-Many if desired.

First let's define the entities:

public class Customer
{
    public int Id { get; set; }

    public int? CurrentApplicationId { get; set; }
    public Application CurrentApplication { get; set; }

    public ICollection<Application> Applications { get; set; }
}

public class Application
{
    public int Id { get; set; }

    public Customer Customer { get; set; }
}

The single interesting part is int? CurrentApplicationId. We need to explicitly define the foreign key for our Zero-to-Many relationship (more on this later). The nullable int (int?) tells EF that this field can be NULL.

EF is usually able to figure out the relationship mappings but in this case we need to explain them to it explicitly:

class DataContext : DbContext
{
    // ctor omitted for brevity

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>(customer =>
        {
            customer.HasMany(entity => entity.Applications)
                .WithOne(relatedEntity => relatedEntity.Customer)
                .OnDelete(DeleteBehavior.Cascade);

            customer.HasOne(entity => entity.CurrentApplication)
                .WithOne()
                .HasForeignKey<Customer>(entity => entity.CurrentApplicationId);
        });
    }

    public DbSet<Application> Applications { get; set; }
    public DbSet<Customer> Customers { get; set; }
}

What's going on in the OnModelCreating method is called fluent API configuration. This topic and conventions is a must to understand and control how EF maps the entities to DB tables.

Based on the mapping EF is able to generate (see code-first migrations) the following DB schema:

CREATE TABLE [Customers] (
  [Id] INTEGER  NOT NULL
, [CurrentApplicationId] bigint  NULL
, CONSTRAINT [sqlite_master_PK_Customers] PRIMARY KEY ([Id])
, FOREIGN KEY ([CurrentApplicationId]) REFERENCES [Applications] ([Id]) ON DELETE RESTRICT ON UPDATE NO ACTION
);
CREATE UNIQUE INDEX [IX_Customers_CurrentApplicationId] ON [Customers] ([CurrentApplicationId] ASC);

CREATE TABLE [Applications] (
  [Id] INTEGER  NOT NULL
, [CustomerId] bigint  NULL
, CONSTRAINT [sqlite_master_PK_Applications] PRIMARY KEY ([Id])
, FOREIGN KEY ([CustomerId]) REFERENCES [Customers] ([Id]) ON DELETE CASCADE ON UPDATE NO ACTION
);
CREATE INDEX [IX_Applications_CustomerId] ON [Applications] ([CustomerId] ASC);

Exactly what we wanted.

Now, how you query the active and inactive applications in this configuration? Something like this:

var customerId = 1;

using (var ctx = new DataContext())
{
    var currentApplication = (
        from customer in ctx.Customers
        where customer.Id == customerId
        select customer.CurrentApplication
    ).FirstOrDefault();

    var pastApplications =
    (
        from customer in ctx.Customers
        from application in customer.Applications
        where customer.Id == customerId && customer.CurrentApplication != application
        select application
    ).ToArray();
}

I suggest you to read through the acticles to be found here to get familiar with EF Core.

As for relational DB modelling this site seems a useful resource.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to display multiple attributes items of a model in list item in rails active admin index page?

From Dev

How do you remove items from several list boxes by removing one item associated with them all?

From Dev

Active Model Serializers: How to pass options to a collection?

From Dev

How to find items that are in one dstore collection but not in another?

From Dev

Post one item from model collection to controller method in MVC

From Dev

Post one item from model collection to controller method in MVC

From Dev

How to add array items in one single item?

From Dev

How to open a collection item only on one client?

From Dev

Fetching items where nested collection contains item(s) form another collection

From Dev

How to specify one attribute of a model inside a collection?

From Dev

How update/remove an item already cached within a collection of items

From Dev

In Rails how to use a model's method for the active record `where`?

From Dev

In Rails how to use a model's method for the active record `where`?

From Dev

Allow only one model in Backbone collection to have an active property at any given time

From Dev

How to split items of a string into two, one contains item start with '-D'?

From Dev

how to decrease dictionary items by one when item is added to the cart in python

From Dev

How to split items of a string into two, one contains item start with '-D'?

From Dev

Add QMap items in a QListWidget and select the item as active

From Dev

How do I add an active class to a list of items when an item is clicked on in Ember?

From Dev

showing two model items in yii2 as a radio list where a user cannot select both but one

From Dev

Can/how would you make a database where two items have multiple relations between them

From Dev

Correct way to model a collection of items in Firebase

From Dev

How to generate and bind a column for each item in the collection property of items used as DataGrid's ItemsSource

From Dev

How to update CustomListView item in Android using Model where the model data is downloaded from internet?

From Dev

Laravel where condition for one item?

From Dev

How can I create a nested list from an existing one where the first x items are the outer items?

From Dev

How can I select from items from two tables with one item only have one value

From Dev

Rails Active Record specify where on relational model

From Dev

Active Record Where Clause For Relation In Model

Related Related

  1. 1

    How to display multiple attributes items of a model in list item in rails active admin index page?

  2. 2

    How do you remove items from several list boxes by removing one item associated with them all?

  3. 3

    Active Model Serializers: How to pass options to a collection?

  4. 4

    How to find items that are in one dstore collection but not in another?

  5. 5

    Post one item from model collection to controller method in MVC

  6. 6

    Post one item from model collection to controller method in MVC

  7. 7

    How to add array items in one single item?

  8. 8

    How to open a collection item only on one client?

  9. 9

    Fetching items where nested collection contains item(s) form another collection

  10. 10

    How to specify one attribute of a model inside a collection?

  11. 11

    How update/remove an item already cached within a collection of items

  12. 12

    In Rails how to use a model's method for the active record `where`?

  13. 13

    In Rails how to use a model's method for the active record `where`?

  14. 14

    Allow only one model in Backbone collection to have an active property at any given time

  15. 15

    How to split items of a string into two, one contains item start with '-D'?

  16. 16

    how to decrease dictionary items by one when item is added to the cart in python

  17. 17

    How to split items of a string into two, one contains item start with '-D'?

  18. 18

    Add QMap items in a QListWidget and select the item as active

  19. 19

    How do I add an active class to a list of items when an item is clicked on in Ember?

  20. 20

    showing two model items in yii2 as a radio list where a user cannot select both but one

  21. 21

    Can/how would you make a database where two items have multiple relations between them

  22. 22

    Correct way to model a collection of items in Firebase

  23. 23

    How to generate and bind a column for each item in the collection property of items used as DataGrid's ItemsSource

  24. 24

    How to update CustomListView item in Android using Model where the model data is downloaded from internet?

  25. 25

    Laravel where condition for one item?

  26. 26

    How can I create a nested list from an existing one where the first x items are the outer items?

  27. 27

    How can I select from items from two tables with one item only have one value

  28. 28

    Rails Active Record specify where on relational model

  29. 29

    Active Record Where Clause For Relation In Model

HotTag

Archive