简体   繁体   中英

Designing tables to avoid circular reference

Working in one project (Catering theme ) when I was designing the database I didn't take care about some thing , and now Is very hard to avoid some kine of errors(Circular error).

Suppose I have following scenario :

I have Meal object that should be composed from a list of semi-finished products (we will call it Product ) and list of simple Resources .

One Product is composed from a list of Resoruces and list of products . So in real example this will look like this:

Meal : Pizza that contains list of Resoruces ( cheese , dough ) and list of Products : in our case will be just :Sauce. Sauce will be composed from List of Resources ( salt , Some cheese , tomato Sauce ) and a List of Products (in our case will be just one "Chopped tomatoes with salt") So now I have following classes:

public class Resource
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }


    public class ProductToProduct
    {
        public int Id { get; set; }
        public Product MainProduct { get; set; }
        public Product Component { get; set; }
        public double Quantity { get; set; }
    }

    public class ProductToResource
    {
        public int Id { get; set; }
        public Product Product { get; set; }
        public Resource Resource { get; set; }
        public double Quantityt { get; set; }
    }

    public class Meal
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IList<MealToProduct> MealToProducts { get; set; }
        public IList<MealToResource> MealToResources { get; set; }

    }

    public class MealToResource
    {
        public int Id { get; set; }
        public Meal Meal { get; set; }
        public Resource Resource { get; set; }
        public double Quantity { get; set; }

    }


    public class MealToProduct
    {
        public Meal Meal { get; set; }
        public Product Product { get; set; }
        public double Quantity { get; set; }
    }

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IList<ProductToResource> ProdcutToResources { get; set; }
        public IList<ProductToResource> ProductToProducts { get; set; }

    }

My problem is in relation between Product to Product .

Suppose I will have Product1, Product2 , Product3 , Product4.

Product 1 will be composed from something and Prodcut2, Product4.

Product2 will be composed from something and Prodcut3.

Prodcut 3 will be composed from something and Prodcut4.

Prodcut 4 will be composed from something and Prodcut1 , in this case when I will try to calcualte Cost for Product1 , or Product 4 I will get an Circular error.

So my problem is in ProductToProduct table. My question is how I must to design tables to avoid this kind of errors .

I AM VERY SORRY FOR MY EXPLICATION BUT IT IS VERY HARD TO EXPLAIN THIS PROBLEM. PLEASE ASK ME IF SOMETHING IS UNCLEAR. THANKS FOR YOUR ATTENTION.

Note:This is not so important for this case but I am working in ASP.Net mvc , orm is Fluent Nhibernate.

Here's an example of a function you could use to detect whether a parent-child relationship exists. I have assumed that the product relationships are described in a table called ProductLink , which has two foreign keys to Product : ParentProductId and ChildProductId .

This function uses a recursive query to determine the complete list of products which are children of the product denoted by the argument @ParentProductId , then does a simple test to see whether @ChildProductId appears in that list.

create function dbo.ProductRelationshipExists
(
    @ParentProductId int,
    @ChildProductId int
)
returns bit
as
begin
    declare @ChildExists bit = 0;

    with ProductChildCTE as
    (
        -- Base case: Get the parent's direct children.
        select ChildProductId from ProductLink where ParentProductId = @ParentProductId

        -- Recursive case: Get the children's children.
        union all
        select
            ProductLink.ChildProductId
        from
            ProductChildCTE
            inner join ProductLink on ProductChildCTE.ChildProductId = ProductLink.ParentProductId
    )
    select @ChildExists = 1 from ProductChildCTE where ChildProductId = @ChildProductId;

    return @ChildExists;
end

When someone tries to insert a record into ProductLink , you could use a test like this to determine whether the proposed parent and child are already in the table as child and parent, respectively, and disallow the insertion if so.

This was just a quick write-up to illustrate one possible approach; I should mention that I don't know how well the performance of this thing will scale as the table gets larger. Hopefully it will suffice for your case. If not, let me know how to improve it.

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