TL/DR: I have two Models each with its own repository, context and controller for MongoDB. How do I build relationships between them similar to how RDBMS would use ForeignKey to reference one model from another.
So I have two models, one referencing another one:
[Validator(typeof(OrgNameValidator))]
public class Org : BaseEntity
{
public string Name { get; set; }
}
public class Portfolio : BaseEntity
{
public string Name { get; set; }
public bool IsPrivate { get; set; }
public Org Organization { get; set; }
}
I use MongoDB as backend so each of the two has their own context, repository and controller (This may be right or wrong, but for the education purposes I am trying to focus on the task of managing relationship between MongoDB documents that is abstracted from the representation at the model/class level).
My attempt is that when I save a Portfolio, at the database level, it will create a document in the Portfolio collection that has a field for Org with ObjectID referencing a document in the Org collection.
So I am trying to POST a new Portfolio:
[HttpPost]
public async Task<IActionResult> Post([FromBody] Portfolio portfolio)
{
try
{
if (ModelState.IsValid)
{
await _repository.AddRecord(portfolio);
return new OkObjectResult(portfolio);
}
else
{
return await Task.FromResult(BadRequest(ModelState));
}
}
catch (Exception ex)
{
return await Task.FromResult(StatusCode(500, ex.Message));
}
}
So there are two scenarios that happen:
When passing Org _Id for Organization field (similar with how some other frameworks let you do this) - you end up with invalid input problem: the Organization field is Org class so it won't validate and I think I am missing some object mapping or something else that potentially comes out of box with AspNetCore.MVC that would allow me to mitigate this.
When giving it all Org details - will save the Org details inline Portfolio document in its own Portfolio collection. I assume this is logical since from the object perspective, Org is an Org so it validates the object and nests it into the document - how would it "know" that it needs to save the document in a different collection via a different repository implementation.
I would assume that I could convert things a little to actually be this (having Organization be represented as string storing it's _id and then working out the logic of retrieving the relevant data via getters in Portfolio class):
public class Org : BaseEntity
{
public string Name { get; set; }
}
public class Portfolio : BaseEntity
{
public string Name { get; set; }
public bool IsPrivate { get; set; }
public string Organization { get; set; }
public getOrganization{get{return _repo<Org>.getOrgById(this.Organization)}}
}
I am still thinking that there must be something I am missing that will allow me to keep the "conventional" model/class structure similar to how I would have it with RDBMS implementations while having a document-oriented storage at the backend.
Another option here is using MongoDBRef type to reference other documents but it requires a bit of coding to align this to be flexible across modelling entities. I looked for MongoDB repository/entity frameworks implementations and found a few (Yarn, MongoRepository, Simple.Data, SharpRepository) but none are compatible with AspNetCore yet.
What is the pattern in asp.net core that allows me to orchestrate object relationships between different models and objects with MongoDB?
Related
I'm currently writing an ASP .NET Core API utilizing OData for querying, and Entity Framework to talk to the database.
I want to separate the domain objects from the DTOs sent to the user, so have also started to use AutoMapper to translate entity framework query results to DTOs I have created.
At this point (while I'm testing), my DTOs and domain objects are the same - just public getter/setter properties. Examples of the DTOs are as follows:
public class NoteDTO
{
public int Id { get; set; }
public string Body { get; set; }
public string Conclusion { get; set; }
public string Title { get; set; }
public ManagerDTO Manager { get; set; }
}
public class ManagerDTO
{
public int Id { get; set; }
public virtual List<ProductDto> Products { get; set; }
}
public class ProductDto
{
public int Id { get; set; }
}
I also have a test method in my NotesController for fetching notes (again, using OData) which is as follows:
[HttpGet]
[EnableQuery]
public IQueryable<NoteDTO> GetMeeting()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Note, NoteDTO>();
cfg.CreateMap<Product, ProductDto>();
cfg.CreateMap<Manager, ManagerDTO>()
.ForMember(md => md.Products, conf => conf.MapFrom(m => m.Products));
});
return _context.Notes.ProjectTo<NoteDTO>(config);
}
I then try and hit my API with the following query:
https://localhost:5001/api/Notes?$select=Id,Body,Conclusion&$top=5&$expand=Manager($select=Id)
However, this fails, and in amongst the stack trace, I'm given the following error message:
System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[System.Tuple`3[TestEntityFramework.DataObjects.ProductDto,Microsoft.EntityFrameworkCore.Query.Internal.MaterializedAnonymousObject,Microsoft.EntityFrameworkCore.Query.Internal.MaterializedAnonymousObject]]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable`1[TestEntityFramework.DataObjects.ProductDto]' of method 'System.Collections.Generic.IEnumerable`1[TestEntityFramework.DataObjects.ProductDto] _ToEnumerable[ProductDto](System.Collections.Generic.IEnumerable`1[TestEntityFramework.DataObjects.ProductDto])'
If I remove the List from the ManagerDTO object and the relevant Product mapping config, the query above works successfully.
I saw this comment on a GitHub issue for what sounds like the same problem, but trying to implement the suggestion hasn't helped (assuming I've understood them correctly): https://github.com/AutoMapper/AutoMapper/issues/2853#issuecomment-482317381
Has anyone else run into this problem? I'm still getting used to AutoMapper so may have missed something obvious, but from searching around this seems to be a fairly uncommon issue and so pointers as to what's going on here have been hard to come by.
I'm open to any other suggestions as to what the best way of translating an OData query to entity framework, then back to a DTO is as well - if what I'm doing here isn't optimal!
Are you using the Automapper Collection Extensions? If not, this should solve your problem: https://github.com/AutoMapper/AutoMapper.Collection
I have a large class that used to hold different information for two different sets of the same class. For example, say a receipt that can be a customer receipt or an internal receipt. All this information is in one giant class because that's how the database is structured, but I want to separate the classes so that I would have a receipt class that holds all the shared information, a customer receipt class, and an internal receipt class. They could share an interface, but the implementations would be different, and that is what is confusing me.
Should there be two separate interfaces that get implemented? So I would have an ICustomerReceipt and IInternalReceipt? I thought there should be one interface with say a Get() and Save() method, and based on the implementation if it's a customer or internal receipt, I get the information specific to the class. I'm a bit lost here.
public class Receipt {
public int ID { get; set; }
public int ReceiptNumber { get; set; }
public List<string> Items { get; set; }
}
public class CustomerReceipt : Receipt {
public string CustomerNumber { get; set; }
public string CustomerEmail { get; set; }
public string CustomerOption { get; set; }
}
public class InternalReceipt : Receipt {
public string InternalNumber { get; set; }
public string InternalEmail { get; set; }
public string InternalOption { get; set; }
}
public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public CustomerReceipt Get(int id) {
// get information about customer receipts here
}
}
public InternalReceiptRepository: IReceiptRepository {
public InternalReceipt Get(int id) {
// get information about internal receipts here
}
}
Basically I just want to return the correct Receipt to a view model in my controller that just has the generic 'ReceiptNumber' or 'ReceiptEmail'. I know it's not the best example, but it's the only one I could come up with.
Don't get tripped up on trying to force two similar things to share a single abstraction (base class or interface). So, I'd recommend what you suggested: create two separate interfaces.
Remember, the point of polymorphism is so you don't have to know what specific (derived/implemented) type an instance is if you're only looking for an instance of the base type/interface. That's it. If you don't need that, then jumping through hoops to force two similar classes to share a base is not worth it.
public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public Receipt Get(int id) {
// get information about customer receipts here
return new CustomerReceipt();
}
}
public InternalReceiptRepository: IReceiptRepository {
public Receipt Get(int id) {
// get information about internal receipts here
return new InternalReceipt();
}
}
Inheritance can be represented on the database in different ways and there are some strategies depending on the ORM you are using.
At the end of the day, using one of the strategies, you can base your repository on the base class and let the ORM act as a proxy to resolve the instance you need, or try to recreate yourself, at the level of the repository, based on a discriminator field, the instances you need
Receipt
ID
ReceiptNumber
CustomerNumber
CustomerEmail
CustomerOption
InternalNumber
InternalEmail
InternalOption
DISCRIMINATOR_FIELD
(most of the ORM do this translation for you), but for you to get the idea, you can keep only one repository to treat all the classes as Receipt and keep your hierarchy as you have it.
public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public Receipt Get(int id) {
var rec = DbContext.Table.Receipt.FirstOrDefault(r => r.id = id);
if(rec.DiscriminatorField == 1) //CustomerReceipt
{
return new CustomerReceipt
{
ID = ...
ReceiptNumber = ...
CustomerNumber = ...
CustomerEmail = ...
CustomerOption = ...
}
}
//all other cases are InternalReceipts
return new InternalReceipt
{
ID = ...
ReceiptNumber = ...
InternalNumber = ...
InternalEmail = ...
InternalOption = ...
}
}
}
The same thing for the Add method, just fill only the fields you need for that object. This composition is basing everything on a discriminator field. I am not suggesting you implement your solution in that way, but with that, you still get on your ViewModel the generic receipt. My suggestion is that you read more about the ORM you are using an how you can represent inheritance there(maybe you are using database first instead of code first and you will need to handle the things manually, because the database was not designed on that way and you need to take a similar approach of what I suggested. But if you have the chance to create your POCO classes and create the database, definitely it deserves to take a look at how they implement the inheritance.
Here I am attaching a link of how this problem is addressed on EntityFramework 6
Inheritance Strategy in Entity Framework 6
Hope this helps
I am making a website and have two databases, one for my application, and another for an external application. By external, I mean it is an opensource application that I want to work with. The application is MVCForum
This external application already has membership integrated. It uses dependency injection (Unity) and uses Entity Framework. Obviously I don't want to destroy the project and would like to be able to have my application run alongside the MVCForum so that when/if it ever gets updated, I can run the updates without too much trouble and without it affecting my application.
So, here is the problem:
I have a MembershipUser class part of an application, call it externamApp.
namespace MVCForum.Domain.DomainModel
{
public partial class MembershipUser : Entity
{
public MembershipUser()
{
Id = GuidComb.GenerateComb();
}
public Guid Id { get; set; }
public string UserName { get; set; }
public virtual IList<MembershipRole> Roles { get; set; }
//I need to have this. A user has one or many trips
public virtual IList<Trip> Trips{ get; set; }
}
}
I also have my own app, let's call it myApp. Within my app, I have a class called Trip.
namespace MyApp.Domain.DomainModel.TripModels
{
public partial class Trip : Entity
{
public Trip()
{
Id = GuidComb.GenerateComb();
}
public Guid Id { get; set; }
public virtual MembershipUser User { get; set; }
public virtual TCCategory Category { get; set; }
}
}
As you can see, MembershipUser has a property:
public virtual IList<Trip> Trips{ get; set; }
This is because a user can have one to many trips...
You can also see that Trip has a property:
public virtual MembershipUser User { get; set; }
But, I would also like to have a user attached to my Trip class.
When Entity Framework pulls an object from the database, it links with that object all the sub-objects. For example, when it pulls out MembershipUser, it will have all the roles of that user attached - because of this property (and the mapping obviously):
public virtual IList<MembershipRole> Roles { get; set; }
I realize that this is a circular reference, but I am hoping someone with more knowledge can offer a good suggestion or perhaps even a solution.
Like you said and well you have a circular dependency, it is not good to have such dependencies and you should not create solutions with that kind of approach.
The first solution that comes to my mind is that you create a new project (a library) that contains information about your membership (I suggest you to go further and create a Data library containing all the data related classes), that way you can reference that project from both your applications and and avoid the circular dependency.
The following class was Auto generated from a template using the Entity Framework Model.
namespace Entities
{
using System;
using System.Collections.Generic;
public partial class Country
{
public Country()
{
this.Regions = new HashSet<Region>();
}
public long CountryId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool Preferred { get; set; }
public System.DateTime LastChanged { get; set; }
public virtual ICollection<Region> Regions { get; set; }
}
}
I have a Wcf web service that returns POX (Xml) and Json only. I am wanting to return my own serialised object like;
public class MyResponseObject
{
public int RequestId {get;set;}
public List<Country> CountryList {get;set;}
//other properties
}
But I don't want to return the Regions ICollection.
The object can then be returned using something like
Newtonsoft.Json.JsonConvert.SerializeObject()
Am I best returning my own serialised POCO object in this manner ?
In projects like these, your classes can be split into two types:
Database entity objects (what Entity Framework works with)
Data contract objects (what WCF or your web-service works with)
While it is possible to use the same objects for both, it is not recommended because the database entity objects are an internal implementation concern that is separate from the external interface (your webservice). You might add or remove columns to your database table and not want your API contracts to change. But usually you'll want to hide information from service-consumers, like a database table Users ( UserId, Password ), you definitely don't want the Password property going out!
Another reason not to is that you later might want to add attributes to your webservice contract classes (e.g. to control output formatting or input validation), adding these to entity objects is painful, if not impossible in some cases.
I know it sounds like a needless duplication of work as the majority of classes will have identical members, but it makes sense from a long-term perspective.
Fortunately tools like AutoMapper can speed-up the process of copying data from your database entity objects to your data contract objects.
From what I have read POCO classes should be persistence ignorant and should not contain references to repositories.
Q1. Given the above, how would I populate the QuestionBlocks collection? I have read that POCO's should contain behavior so you don't end of with an anemic model, so I'm kind of confused as how one is supposed to do that without persistence. If that's the case then what kind of behavior would you put in a POCO?
Ex:
public class Survey
{
public int SurveyId { get; set; }
public string Title { get; set; }
public int BrandId { get; set; }
public DateTime Created { get; set; }
public List<SurveyQuestionBlock> QuestionBlocks { get; set; }
[ResultColumn]
public string Name { get; set; }
/// <summary>
/// Constructor
/// </summary>
public Survey()
{
Created = DateTime.Now;
QuestionBlocks = new List<SurveyQuestionBlock>();
}
}
I would append another view: POCO states for objects which are not dependent on any framework. The wiki definition of a POJO is much more meaningful to me then the one for POCO:
http://en.wikipedia.org/wiki/Plain_Old_Java_Object
To paraphrase the wiki definition of the POJO, we can say that POCO object might not be forced to:
I. Extend prespecified class:
public class MyClass : AnyFramework.ObjectBase {...
II. Implement prespecified interfaces
public class MyClass : AnyFramework.IHaveDependency {...
III. Contain prespecified attribute
[AnyFramework.KeyAttribute]
public class MyClass {...
Given this (almost anything else is allowed) in the meaning of taking care about the object state. Other words, if object will check Business logic, it is correct.
But any POCO object can be used in a framework. Today it is mostly for ORM which is responsible for persistence. All application tiers are working with POCO objects, while data layer is responsible for loading and persisting (CRUD). This is mostly done via Proxies of these POCO objects.
So, POCO could be used as full business object, which can take care about itself (check correctness of collection items, properties...). This makes it different from DTO
Given the above, how would I populate the QuestionBlocks collection?
When reading from a database, the persistence infrastructure should populate the QuestionBlocks collection - reconstitution. Reconstruction should not invoke behavior, it should only set appropriate fields on the POCO. This is the responsibility of the repository. A repository is typically referenced from an application service, which sets up the stage for invoking entity behavior.
If that's the case then what kind of behavior would you put in a POCO?
The behavior in the POCO entity should be concerned with making changes to the entity itself as well as maintaining invariants - ie ensuring the integrity of the entity. In your example, the simplest kind of behavior on the POCO should be method for adding a new question block to the collection on the survey. Ideally, you would make many of the properties on the survey entity read-only:
public class Survey
{
public int SurveyId { get; private set; }
public string Title { get; private set; }
public int BrandId { get; private set; }
public DateTime Created { get; private set; }
public IList<SurveyQuestionBlock> QuestionBlocks { get; private set; }
public string Name { get; private set; }
public void AddQuestionBlock(string questionBlockInfo)
{
this.QuestionBlocks.Add(new SurveyQuestionBlock(...));
}
public Survey()
{
Created = DateTime.Now;
QuestionBlocks = new List<SurveyQuestionBlock>();
}
}
The persistence layer should be able to set the values of the read-only properties via reflection. You can go a step further and only expose the question blocks collection as a read-only collection to ensure that it can only be modified from within the entity itself.