MongoDb serialize generic types (classes) - c#

What is the general advice on serializing something like this in MongoDb
public class BaseCategorization<T> where T : BaseCategory
{
public BaseCategorization()
{
Type = typeof(T).Name;
}
public BaseCategorization(int id)
{
Id = id;
Type = typeof(T).Name;
}
...
}
I use it like this:
_documentsProvider.Save<BaseCategorization<ProductCategory>>(newProductCategorization);
where ProductCategory : BaseCategory and BaseCategory is abstract.
The above seems to work, only problem is the strange name of the resulting collection, BaseCategorization'1, and the fact that I don't know whether this design is fine by MongoDb terms.

You certainly can store all of your documents in one collection, however it is probably easier and cleaner in the long run to only store one type in a collection (from a C# perspective). You can do this by creating a class with an Extension Method on MongoDatabase.
public static class MyDatabase
{
public static MongoCollection<T> GetCollection<T>(this MongoDatabase db)
{
var name = typeof(T).Name;
return db.GetCollection<T>(name);
}
}
Then you can just call GetCollection with your type on it and the name will be hidden from your general code. You can also create something like this to abstract things a little bit further:
public class MyDatabase
{
private MongoDatabase _db;
public MyDatabase(MongoDatabase db)
{
_db = db;
}
public MongoCollection<object> Objects
{
get
{
return _db.GetCollection<object>();
}
}
}
With this you can just do
var client = new MongoClient();
var server = client.GetServer();
var db = server.GetDatabase("MyDb");
var myDb = new MyDatabase(db);
myDb.Objects.Find();
This Find will map to execute against the Objects collection, simply replace <object> with your type and give the collection a name.

Related

Automapper initialize for T type

I want to have generic method to get data from database and pass model of how output data should look like.
I wrote simple method:
public IEnumerable<T> GetUsers<T>()
{
Mapper.Initialize(cfg =>
cfg.CreateMap<IQueryable<User>, IQueryable<T>>());
return OnConnect<IEnumerable<T>>(db =>
{
return db.Users.ProjectTo<T>().ToList();
});
}
Now I expected that I can do this:
var users = repo.GetUsers<UserViewModel>(); // it should be IEnumerable<UserViewModel>
var anotherUsers = repo.GetUsers<AnotherUserViewModel>(); // it should be IEnumerable<AnotherUserViewModel>
But I cant reinitialize automapper again. What should I do to make it working?
Initialize automapper only once per application startup.
You should know what types can be mapped from User already at the moment when you design a code in that case you can register all of them at a startup like this:
Mapper.Initialize(cfg => {
cfg.CreateMap<User, UserDto1>();
cfg.CreateMap<User, UserDto2>();
...
cfg.CreateMap<User, UserDtoN>();
});
Even if you will achieve it - it will not make a sense to try to map User to Order, but your architectural design will give that possibility
If you still want to do it(like I wrote in comments) - you can add somekind of marker attribute for Instance - MappableFrom(Type from), mark all DTO objects that can be used in scope of automapper. Then on initialization of your application - scan the assembly for all types that contains that attribute and register in Automapper.
You can use Profile to create all mappers follow this link http://docs.automapper.org/en/stable/Configuration.html
Another approach you can initialize in a static constructor all the mapping you want by using some naming convention
In the below code, I'm mapping from same object type to same object type
// Data or View Models
public class AddressViewModel : BaseViewModel
{
public string Address {get;set;}
public AddressViewModel()
{
this.Address ="Address";
}
}
public class UserViewModel : BaseViewModel
{
public string Name {get;set;}
public UserViewModel()
{
this.Name ="Name";
}
}
public class BaseViewModel
{
}
Repository -- here I'm using same view model you should create Models here
public class CrudRepo
{
public IEnumerable<T> GetData<T>() where T : class, new ()
{
var data = new List<T> { new T() };
return AutoMapper.Mapper.Map<IEnumerable<T>>(data);
}
}
Then in of the static constructor initialize the mappers
static HelperClass()
{
// In this case all classes are present in the current assembly
var items = Assembly.GetExecutingAssembly()
.GetTypes().Where(x =>
typeof(BaseViewModel)
.IsAssignableFrom(x))
.ToList();
AutoMapper.Mapper.Initialize(cfg =>
{
items.ForEach(x =>
{
// Here use some naming convention or attribute to find out the Source and Destination Type
//Or use a dictionary which gives you source and destination type
cfg.CreateMap(x, x);
});
});
}
Now you can create the instance of crud repository and get mapped items
var userRepo = new CrudRepo();
var users = userRepo.GetData<UserViewModel>();
var address = addressRepo.GetData<AddressViewModel>();
Note: As long as property names and types are same the data will be mapped else you have to create ForMember

Testing against Entity Framework InMemory

I'm currently testing an Entity Framework's DbContext using the In-Memory Database.
In order to make tests as atomic as possible, the DbContext is unique per test-method, and it's populated with initial data needed by each test.
To set the initial state of the DbContext, I've created a void SetupData method that fills the context with some entities that I will use in the tests.
The problem with this approach is that the objects that are created during the setup cannot be accessed by the test, because Entity Framework will assign the Ids itself, that are unknown until run-time.
To overcome this problem, I've thought that my SetupData method could become something like this:
public Fixture SetupData(MyContext context)
{
var fixture = new Fixture();
fixture.CreatedUser = new User();
context.Users.Add(fixture.CreatedUser);
context.SaveChanges();
return fixture;
}
public class Fixture
{
public User CreatedUser { get; set;}
}
As you see, it's returning an instance of what I called "Fixture". (I don't know if the name fits well).
This way, the SetupData will return an object (Fixture) with references to the entities. Thus, the test can use the created object. Otherwise, the object will be impossible to identify, since the Id isn't created until the SaveChanges is called.
My question is:
Is this a bad practice?
Is there a better way to reference initial
data?
I prefer this approach:
public void SetupData(MyContext context)
{
var user = new User() { Id = Fixture.TEST_USER1_ID, UserName = Fixture.TEST_USER1_NAME };
context.Users.Add(user);
context.SaveChanges();
}
public class Fixture
{
public const int TEST_USER1_ID = 123;
public const string TEST_USER!_NAME = "testuser";
}
Your approach is probably fine, too, but you probably will want to know the user ID somewhere in your tests and this makes it very easy to specify it in a single known location so that it won't change if for instance you later on change your test data and the order in which you add users.
This is not a bad practice. In fact it is a good approach to create readable Given-When-Then tests. If you consider:
splitting your SetupData method
renaming it
possibly changing to a extension method
public static MyContextExtensions
{
public static User Given(this MyContext #this, User user)
{
#this.Users.Add(user);
#this.SaveChanges();
return user;
}
public static OtherEntity Given(this MyContext #this, OtherEntity otherEntity)
{
// ...
}
// ...
}
you can then write (a conceptual example, details need to be reworked to match your implementation):
[Test]
public GivenAUser_WhenSearchingById_ReturnsTheUser()
{
var expectedUsername = "username";
var user = _context.Given(AUser.WithName(expectedUsername));
var result = _repository.GetUser(user.Id);
Assert.That(result.Name, Is.EqualTo(expectedUsername));
}
... and similarly for other entities.

Persisting the state pattern using Entity Framework

I am currently developing a project in MVC 3. I've separated my concerns so there are projects such as Core, Repository, UI, Services etc. I have implement the Repository, UnitOfWork and most importantly the State pattern.
I am using Entity Framework 4.3 to persist my data and I have come across a rather annoying situation involving the persistence of the current state. Below are some class examples:
public class Request
{
public int RequestId { get; set; }
public State CurrentState { get; set; }
}
public abstract class State
{
[Key]
public string Name {get; set;}
public virtual void OpenRequest(Request request)
{}
public virtual void CloseRequest(Request request)
{}
}
public class RequestIsOpenState : State
{
public RequestIsOpenState()
{
this.Name = "Open";
}
public override void CloseRequest(Request request)
{
request.CurrentState = new RequstIsClosedState();
}
}
public class RequestIsClosedState : State
{
public RequestIsClosedState()
{
this.Name = "Closed";
}
public override void OpenRequest(Request request)
{
request.CurrentState = new RequstIsOpenState();
}
}
Using the above example I will get a primary key violation exception because it tries to create a NEW state in the States table.
Because the state change is done within the domain layer, I can't just 'get' the state from the repository and set it using the foreign key by doing something like this:
Request request = unitOfWork.RequestRepository.Find(1);
request.CurrentState = unitOfWork.StateRepository.Find("Closed");
I'm aware I have the option of not mapping the state property, and persist a string property in the request class and then convert them back and forth through a factory on a get and set when the entity is hydrated (see this answer).
All I want to do is persist the state class, so when the request is returned I can access the state methods immediately without having loads of EF stuff polluting my domain layer just to handle one persistence issue. Another benefit of which would be it gives me the added bonus of having a table in SQL to query against known states.
I think you can improve it by caching the State instances creating it only once, to avoid making the list each time and avoid the foreach:
public static class StateFactory
{
private static Dictionary<string, State> statesCache = FindAllDerivedStates();
public static State GetState(string stateTypeName)
{
return statesCache[stateTypeName];
}
private static Dictionary<string, State> FindAllDerivedStates()
{
var derivedType = typeof(State);
var assembly = Assembly.GetAssembly(typeof(State));
return assembly.GetTypes().Where(t => t != derivedType && derivedType.IsAssignableFrom(t))
.Select(t => (State)Activator.CreateInstance(t))
.ToDictionary(k => k.Name);
}
}
I've made some progress by simplifying the factory back to basics and by implementing it in such a way that you would never really know that a factory is being used. Although It's not what I was looking for, it is so refined and streamlined the only downside is I still don't have a list of ALL states within the SQL database, there are however many possible work arounds for this. Anyway... my compromise:
The State Factory:
public static State GetState(string stateTypeName)
{
var list = FindAllDerivedStates();
dynamic returnedValue = new NullState();
foreach(var state in list)
{
if(state.Name == stateTypeName) returnedValue = (State)Activator.CreateInstance(state);
}
return returnedValue
}
private static List<Type> FindAllDerivedStates()
{
var derivedType = typeof(State);
var assembly = Assembly.GetAssembly(typeof(State));
return assembly.GetTypes().Where(t => t != derivedType && derivedType.IsAssignableFrom(t)).ToList();
}
Now the request needs two properties, a persisted string and a State class. Make sure the State class is not mapped.
public class Request
{
public string StateString { get; set; }
[NotMapped] or [Ignore]
public State CurrentState
{
get
{
return StateFactory.GetState(this.StateString);
}
set
{
this.State = value.GetType().Name;
}
}
}
Now because of the new simplistic implementation, saving the state is as easy as;
request.CurrentState = new OpenState();
and getting the state will always return the methods. Without any extra work you can return an entity and excess the properties. For example if you want output the public string;
request.CurrentState.StateName;
Now I've still got to implement a little work around to add a list of states to my SqlDb but that's not the end of the world. It seems this is the only solution. Or should I say best solution. I'll keep my eyes peeled for a better version.

How to Cast DBSet to Interface in Anonymous Method - E.F

I have a number of tables in my SQL DB that store basic KVP data. they all have the pattern of Id(int), Description(varchar(..)).
I require them all at one stage or another in my MVC application and i am trying to create an anonymous method that will take the type of entity class and return a list of that items data. I would like to be able to use this method for any number of tables in my database without having to extend the methods i am writing by too much.
Example Data:
Id: 1, Description: Red
Id: 2, Description: Blue
Id: 3, Description: Green
ISet Implementation:
public interface ISet
{
int Id { get; set; }
string Description { get; set; }
}
Possible Method Implementation
public static IList<T> BuildSet<T>()
{
using (var db = new somethingEntities())
return db.Set(typeof(T)).Cast<ISet>().Select(c => new { c.Id, c.Description }).ToList();
}
Usage
var data = BuildSet<YourType>();
Runtime Error
Cannot create a DbSet<ISet> from a non-generic DbSet for objects of type 'YourType'.
Does anyone know how to do this?
Thanks.
I assume that the DbSet's are small as ToList() will fetch all the results in one go?
However, here's a simpler version of your code (you specify the interface ISet in the generic type constraint):
public static IList<ISet> BuildSet<T>()
where T : class, ISet
{
using (var db = new somethingEntities())
return db.Set<T>().ToList();
}
There's also the option of an extension method for your DbContext:
public IEnumerable<ISet> BuildSet<T>(this DbContext context)
where T : class, ISet
{
return context.Set<T>().AsEnumerable();
}
which you can then use within the lifetime of your context, possible for a more efficient operation. (I know I'm assuming too much but I feel it's useful information anyway.)
public void SomeOperation()
{
using (var db = new somethingEntities())
{
foreach (var item in db.BuildSet<SimpleSet>())
{
//do something with item
//SaveChanges() every 100 rows or whatever
}
}
}
Problem solved.
Method Declaration
public static List<ISet> BuildSet<T>() where T : class
{
using (var db = new somethingEntities())
return db.Set<T>().ToList().Cast<ISet>().ToList();
}
Usage
var data = ...BuildSet<YourType>();

Linq 2 SQL - A Better way of doing this

I have a repository base class that gets called from my controllers in my mvc application
Each controller gets it own repository
like this
public class ServiceRepository : Bluegrass.Mvc.RepositoryBase<Models.Service>
{
public ServiceRepository()
{
this._db = new iSppms.Models.iSppmsDataContext();
}
}
And gets used like
internal DataAccess.ServiceRepository repository =
new iSppms.DataAccess.ServiceRepository();
public ActionResult Index()
{
var viewData = new ViewData.ServiceIndexViewData(
repository.GetItems<Models.Service>());
return View(viewData);
}
Where I am wanting to do is not have to pass the model through as the RepositoryBase is already of type Models.Service
I am looking for a better way to structure this.
public class RepositoryBase<T> where T : class
{
public DataContext _db;
public List<T> GetItems<T>() where T : class, Interfaces.IModel
{
var table = _db.GetTable<T>();
var data = table.Where(t => !t.Deleted);
return data.ToList();
}
Can you add the IModel bit to RepositoryBase<T>, and make GetItems<T> non-generic? Note: it is already a bad idea to re-use the generic token T (which is different in GetItems):
public class RepositoryBase<T> where T : class, Interfaces.IModel
{
public DataContext _db;
public List<T> GetItems()
{
var table = _db.GetTable<T>();
var data = table.Where(t => !t.Deleted);
return data.ToList();
}
}
Perhaps this Repository Base Class article could help?

Categories

Resources