Pergunta

I've built a nice repository layer around a db4o database to store Product objects, which relate to Manufacturer objects in a one-to-many relationship, i.e.:

public class Manufacturer
{
    public string Name { get; set; }
}

public class Product // simplified
{
    public string Name { get; set; }
    Manufacturer Manufacturer { get; set; }
}

So far I really like db4o. The problem I have is preventing data duplication without resorting to IDs.

When implementing references like manufacturers using SQL Server, my data models would contain a unique ID field, and in turn my Product class would be dirtied up with a ManufacturerID. I imagined that using an object database like db4o would reduce the impedance mismatch between a relational DB and objects, but without IDs, there is no way to tell one object from another when editing it.

Is there an elegant way to share a manufacturer between products without duplicating data? Or should I just use a relational DB?

Foi útil?

Solução

You can add an unique index to db4o in your config.

configuration.Common.ObjectClass(typeof (Manufacturer)).ObjectField("<Name>k__BackingField").Indexed(true);
configuration.Add(new UniqueFieldValueConstraint(typeof(Manufacturer), "<Name>k__BackingField"));

This way it is not possible to have two different Manufacturer object with the same name in your db. The field name have to be "k__BackingField"because you are using auto properties. Of course you could add an integer ID, and index it the same way.

Outras dicas

The basic things first. db4o manages objects by their object-identity. When you store the same object-instance again, db4o will update that object in the database. The same applies to references. When two different objects refer to the same object, they will actually refer to the same object in the database. In your example: When two different product refer to the same Manufacturer-instance, they will also refer to the same Manufacturer in the database. This is achieved by having a table in the back-ground which keeps track of the objects.

Now this approach has issues. As soon as you serialize objects (web-application, web-services etc), or close the object-container, db4o forgets which object in memory belongs to which object. Then it doesn't recognizes a existing object anymore and just stores is as a new object. This means that you should never load and store a object with different object container instance. And that you probably need IDs to recognizes objects. For example to recognize a object across web-requests. A easy solution is to use Guids to give an unique id to an object.

Back to your question. To share the a manufacturer between products you simply point it to the same manufacturer. Like this:

Product newShinyProduct = new Product(); // the new thing
// Get a existing product or manufacturerer, doesn't matter
Product oldProduct = (from p in container.AsQueryable<Product>()
                     where p.Name == "Get a product"
                     select p).First();

// now just assigne the existing manufacturer to the new product
// this product will now refer to the same manufacturer
// and db4o will store this that way. The manufacturer isn't doublicated.
newShinyProduct.Manufacturer = oldProduct.Manufacturer;
// store the new product in the database.
container.Store(newShinyProduct);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top