2
votes

We share a single poco's with

  • ServiceStack WebServices
  • ServiceStack Orm with MySQL
  • Xamarin mobile client that uses Sqlite.net.

Problem is the shared classes have become a mess.

        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
#if __MOBILE__
        [Indexed]
#else
        [Index]
#endif
        public string UserAccountId { get; set; }
#if __MOBILE__
        [Indexed]
#else
        [Index]
#endif

And if it's not bad enough already, i need to

  • Constrain the length of each field in the database....
  • Save these objects in MongoDb. Fortunately, they have an AutoMapper class that does this at runtime.

Not sure what to do. My Failed ideas include:

  • Try to use: [Conditional("DEBUG")]. But it does nothing for this

  • It appears that sqlite.net uses its own attribute

    [AttributeUsage (AttributeTargets.Property)] public class IndexedAttribute : Attribute

    So it won't find the Mysql [Index] attribute

  • Could try to include two attributes on each property

    [Indexed] [Index] public string UserAccountId { get; set; }

  • I tried to turn it into a two one line'ers but c# VS complains

#if __MOBILE__ [Indexed]  #endif 
#if __MOBILE__ [Index]    #endif

In the end, the only approach that ** APPEARS ** will work is to just keep the interface as the single definition of the class and have many concrete classes that get decorated differently.

Any Ideas??

4
It's not a POCO if you have all those attributes on there. Probably a strong point in favor of using a fluent model builder rather than attributes.mason
Your right, its not a poco. Q: I assume i would need to build the ModelBuilder class myself. Is there some general purpose framework that i could use as an overlay? I assume the one in EntityFramework is not going to work.mbalsam
I am not familiar with ServiceStack.OrmLite so unfortunately I don't know what your options are there.mason
Apparently we can keep both defined. So this syntax is valid [Indexed,Index] public string UserAccountIdmbalsam

4 Answers

4
votes

If you were to architect your code as per Uncle Bob's Clean Architecture, you wouldn't attempt to have a single representation to be used for many different purposes, as it causes your dependencies to point outwards from high-level policy towards outer circles.

Clean Architecture

Source: https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

Effectively, you could put an Entity in the centre circle, along with enterprise business rules, but the DTO you use to store/retrieve data for a particular database should be way out in your "frameworks and drivers" circle.

All of those database-specific attributes belong on DTOs in the blue circle, not on the entities in the centre.

0
votes

So, Uncle Bob and Fenton's suggestion is basically my last choice. Make changes to the Interface.

I will user Re-sharper to updates all classes the classes..

This should work.

namespace Evaluation.Entitys
{
    public interface IUserEntity
    {
        string UserAccountId { get; set; }
    }

    public class UserEntity : IUserEntity
    {
        public string UserAccountId { get; set; }

        public UserEntity()
        {

        }
    }

    public class UserEntityTransport : IUserEntity
    {
        public string UserAccountId { get; set; }

        public UserEntityTransport(IUserEntity e)
        {
            UserAccountId = e.UserAccountId;
        }
    }
}
#if __MOBILE__

namespace Evaluation.Moible 
{


    using SQLite;
    using SQLite.Net;
    public class UserEntityMobileDB : IUserEntity
    {
        [Index]
        public string UserAccountId { get; set; }
        public UserEntityMobileDB(IUserEntity e)
        {
            UserAccountId = e.UserAccountId;
        }
    }
}
#endif

#if __WIN32__
namespace Evaluation.Server
{
    using Evaluation.Entitys;
    using ServiceStack.DataAnnotations;
    using SQLite;

    public class UserEntityServerDB : IUserEntity
    {
        [Indexed]
        public string UserAccountId { get; set; }

        public UserEntityServerDB(IUserEntity e)
        {
            UserAccountId = e.UserAccountId;

        }
    }
}
#endif 

This should work.

Drawbacks

  1. Need to maintain multiple 4x copy constructors, at the controller level.
  2. One class is now 4 classes.
0
votes

Mason's suggestion would be to create a fluent like Model Builder. Since this does not currently exist ??? in ServiceStack.OrmLine and SqlLite.net I assume i would have to build it.

I found this code sample from entity framework.

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name) 
    .HasColumnAnnotation( 
        "Index",  
        new IndexAnnotation(new IndexAttribute("IX_Name") { IsUnique = true }));

My psudocode version would look like:

modelBuilder 
    .Entity<UserEntity>() 
    .Property(t => t.UserAccountId) 
    .AddColumnIndex(new IndexAnnotation(new IndexAttribute("IX_Name") {});
0
votes

Apparently this syntax is valid and should also work.

using SQLite;
using ORMLite = ServiceStack.DataAnnotations;

[ORMLite.PrimaryKey, ORMLite.AutoIncrement]
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int Id { get; set; }

[Indexed,Index]
public string UserAccountId { get; set; }