I have configured this two entities:
Host.cs
public class Host : FullAuditedEntity<int>
{
[Required]
public string Name { get; set; }
public List<HostLine> HostLines { get; set; }
}
HostLine.cs
public class HostLine: FullAuditedEntity<int>
{
[Required]
public string Name { get; set; }
public Host Host { get; set; }
}
Manually, I inserted in the DB one tuple for Host and HostLine, linking them accordingly.
select Id, Name from [MyDB].dbo.Hosts;
Id | Name
-----------
1 | Host1
select Name, HostId from [MyDB].dbo.HostLines;
HostId | Name
------------------
1 | HostLine1
The HostLine's FK to the Host table is configured as you can see in the screenshot below.
Then, I implemented a simple Service which extends AsyncCrudAppService to provide CRUD operation on both the Host and HostLine entities.
public class HostsAppService : AsyncCrudAppService<Host, HostDto, int, PagedResultRequestDto, CreateHostDto, HostDto>, IHostsAppService
{
public HostsAppService(IRepository<Host> repository)
: base(repository)
{
}
protected override HostDto MapToEntityDto(Host entity)
{
return base.MapToEntityDto(entity);
}
}
I added the override to the method MapToEntityDto in order to see the data read from the DB (it will be removed).
When I call the Get REST method of the service via the Angular client I can reach the MapToEntityDto() method, but the Host entity does not have a value for the HostLines List field.
So it seems that the Host repository is not reading the linked data from the HostLine table.
Am I lacking some kind of configuration to let the Host repository read also the HostLine data?
Thank you
You need to include the HostLines manually with the below code.
public class TaskAppService : AsyncCrudAppService<Host, HostDto, int, PagedResultRequestDto, CreateHostDto, HostDto>, IHostsAppService
{
//...
protected override IQueryable<Task> CreateFilteredQuery(GetAllTasksInput input)
{
return base.CreateFilteredQuery(input).Include(x=>x.HostLines);
}
//...
}
Further information see https://aspnetboilerplate.com/Pages/Documents/Application-Services#crud-permissions
Related
I currently have a class with around 40 dependency injection. It is a hard to maintain and unit test. I am not sure a good way around.
The code is done for any type of application process that is needed to process (New License, License Renewal, Student Registration, ...), there are around 80 different types applications and what sections are associated with each application type is determined by a database table.
I have a class with all of the possible properties, there are a several more than listed but you should get the idea. Each the properties have their own set of properties that are basic data types or object pointing to other classes.
class Application
{
[JsonProperty(PropertyName = "accounting")]
public Accounting Accounting { get; set; }
[JsonProperty(PropertyName = "application")]
public Application Application { get; set; }
[JsonProperty(PropertyName = "applicationType")]
public ApplicationType ApplicationType { get; set; }
[JsonProperty(PropertyName = "document")]
public List<Attachment> Document { get; set; }
[JsonProperty(PropertyName = "employment")]
public List<Employment> Employment { get; set; }
[JsonProperty(PropertyName = "enrollment")]
public Enrollment Enrollment { get; set; }
[JsonProperty(PropertyName = "individualAddressContact")]
public IndividualAddressContact IndividualAddressContact { get; set; }
[JsonProperty(PropertyName = "instructors")]
public List<Instructor> Instructors { get; set; }
[JsonProperty(PropertyName = "license")]
public License License { get; set; }
[JsonProperty(PropertyName = "licenseRenewal")]
public LicenseRenewal LicenseRenewal { get; set; }
[JsonProperty(PropertyName = "MilitaryService")]
public List<MilitaryService> MilitaryService { get; set; }
[JsonProperty(PropertyName = "paymentDetail")]
public PaymentDetail PaymentDetail { get; set; }
[JsonProperty(PropertyName = "photo")]
public List<Attachment> Photo { get; set; }
[JsonProperty(PropertyName = "portal")]
public Portal Portal { get; set; }
[JsonProperty(PropertyName = "section")]
public List<Section> Section { get; set; }
[JsonProperty(PropertyName = "testingCalendar")]
public TestingCalendar TestingCalendar { get; set; }
[JsonProperty(PropertyName = "testingScore")]
public List<TestingScore> TestingScore { get; set; }
[JsonProperty(PropertyName = "USCitizen")]
public USCitizen USCitizen { get; set; }
}
So this class is sent/received to an Angular 10 front end using Web API's.
When an application is requested the sections and the different properties are initiated and if the application has be started the progress will be reloaded. So it is possible some of properties will be pulled from the database and sent to the Angular app.
So I have something such as
Load(applicationTypeId, applicationId)
{
Get the sections for the application type
For each section in the sections
switch sectionid
case Documents
Load all of the documents required for the application type and get any documents uploaded
case Accounting
Load the payment details, if no payment made calculate the payment
case IndividualAddressContact
Load the person name/address/contact and set a few defaults if the person hasn't started.
.....
next
}
Save()
{
Save the application
switch current section
case Documents
Save all of the documents for the application
case Accounting
Save the payment details for the application
case IndividualAddressContact
Save the person name/address/contact for the application
.....
get the next section
Update the application current section
}
I have put all of the items in the switch into their own classes but in the end I still have 1 point for serialization/deserialization and still end up with to many dependencies injected. Creating a unit test with over 40 dependencies seems hard to maintain and given I won't know which properties will/won't used until an application is requested and loaded from database. I am unsure how to get around the switch, without at some point and time having to have all of the dependencies injected into 1 class.
I would appreciate some ideas of how to get around this.
"I currently have a class with around 40 dependency injection..." - Oh my gosh!
"It is a hard to maintain and unit test..." - I don't doubt that in the least!
SUGGESTED REFACTORING:
Create a class that manages "Applications" (e.g. "ApplicationManager").
Create an abstract class "Application".
One advantage of "abstract class" over "interface" here that you can put "common code" in the abstract base class.
Create a concrete subclass for each "Application" : public class NewLicense : Application, public class LicenseRenewal : Application, etc. etc.
... AND ...
Use DI primarily for those "services" that each concrete class needs.
I'll bet the constructors for your individual concrete classes will only need to inject three or four services ... instead of 40. Who knows - maybe your base class won't need any DI at all.
This is actually a design we're actually using in one of our production systems. It's simple; it's robust; it's flexible. It's working well for us :)
I would recommend using convention over configuration principle, with the Service Locator.
Declare something like IApplicationHandler interface in your program, e.g.
public interface IApplicationQueryHandler
{
Application Populate(Application application);
}
public interface IApplicationSaveHandler
{
Bool Save(Application application);
}
Then, write pieces of your code, with dependencies and such, e.g.
public class AccountingApplicationQueryHandler : IApplicationQueryHandler
{
public Application Populate(Application application) {
//// Load the payment details, if no payment made calculate the payment
return application;
}
}
public class AccountingApplicationSaveHandler : IApplicationSaveHandler
{
public Bool Save(Application application) {
//// Save the payment details for the application
return true; // this just flags for validation
}
}
// repeat for all other properties
Then in your controller, do something like
public class ApplicationController: Controller
{
public readonly IServiceProvider _serviceProvider;
public ApplicationController(IServiceProvider sp) {
_serviceProvider = sp;
}
public Application Load(string applicationTypeId, string applicationId)
{
var application = new Application(); // or get from db or whatever
var queryHandlers = _serviceProvider.GetServices(typeof(IApplicationQueryHandler));
foreach(var handler in queryHandlers) {
application = handler.Populate(application);
}
return application;
}
[HttpPost]
public bool Save(Application application)
{
var result = true;
var saveHandlers = _serviceProvider.GetServices(typeof(IApplicationSaveHandler));
foreach(var handler in queryHandlers) {
result = handler. Save(application);
}
return result;
}
}
You would need to register your handlers, which you can do e.g. like so:
var queryHandlers = Assembly.GetAssembly(typeof(IApplicationQueryHandler)).GetExportedTypes()
.Where(x => x.GetInterfaces().Any(y => y == typeof(IApplicationQueryHandler)));
foreach(queryHandler in queryHandlers) {
services.AddTransient(typeof(IApplicationQueryHandler), queryHandler);
}
// repeat the same for IApplicationSaveHandler
Now finally, you can write unit tests for part of the code like so
[TestClass]
public class AccountingApplicationQueryHandlerTests
{
[TestMethod]
public void TestPopulate()
{
// arrange
var application = new Application();
var handler = new AccountingApplicationQueryHandler(); // inject mocks here
// act
var result = handler.Populate(application);
// Assert
Assert.AreEqual(result. PaymentDetail, "whatever");
}
}
And you can test that your controller calls the right things by mocking IServiceProvider and injecting that with a couple of dummy handlers to confirm they are called correctly.
Following zaitsman's answer you also could create AggregatedApplicationQueryHandler and AggregatedApplicationSaveHandler and pass collection of concrete implementation of IApplicationQueryHandler and IApplicationSaveHandler to its constructor.
Then you don't need foreach loop inside controller(you loop over handlers inside aggregated handler) and always have only one handler passed to controller. Passing its by constructor parameter shouldn't be so much painful.
You also could create facade over some small services and aggregate theirs functions into one bigger facade service.
I am very new to C# and ServiceStack and I am working on a small project that consists on calling a third party API and loading the data I get back from the API into a relational database via ServiceStack's ORMLite.
The idea is to have each endpoint of the API have a reusable model that determines how it should be received in the API's response, and how it should be inserted into the database.
So I have something like the following:
[Route("/api/{ApiEndpoint}", "POST")]
public class ApiRequest : IReturn<ApiResponse>
{
public Int32 OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public String ApiEndpoint { get; set; }
}
public class ApiResponse
{
public Endpoint1[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
public class Endpoint1
{
[AutoIncrement]
public Int32 Id { get; set; }
[CustomField("DATETIME2(7)")]
public String PurchaseDate { get; set; }
[CustomField("NVARCHAR(50)")]
public String Customer { get; set; }
[CustomField("NVARCHAR(20)")]
public String PhoneNumber { get; set; }
public Int32 Amount { get; set; }
}
My first class represents the API's request with its route, the second class represents the API's response. The API's response is the same for all endpoints, but the only thing that varies is the structure of the Data field that comes back from that endpoint. I've defined the structure of one of my endpoints in my Endpoint1 class, and I am using it in my API's response class. As you can see, I am also defining a few attributes on my Endpoint1 class to help the ORM make better decisions later when inserting the data.
Ok, so the issue is that I have about 15 endpoints and I don't want to create 15 ApiResponse classes when I know the only thing that changes is that first Data field in the class.
So I made something like this:
public class DataModels
{
public Type getModel(String endpoint)
{
Dictionary<String, Type> models = new Dictionary<String, Type>();
models.Add("Endpoint1", typeof(Endpoint1));
// models.Add("Endpoint2", typeof(Endpoint2));
// models.Add("Endpoint3", typeof(Endpoint3));
// and so forth...
return models[endpoint];
}
}
I would like for getModel() to be called when the request is made so that I can pass in the ApiEndpoint field in the ApiRequest class and store the type that I want my Data field to have so that I can dynamically change it in my ApiResponse class.
In addition, there is the ORM part where I iterate over every endpoint and create a different table using the model/type of each endpoint. Something like this:
endpoints.ForEach(
(endpoint) =>
{
db.CreateTableIfNotExists<Endpoint1>();
// inserting data, doing other work etc
}
);
But again, I'd like to be able to call getModel() in here and with that define the model of the specific endpoint I am iterating on.
I've attempted calling getModel() on both places but I always get errors back like cannot use variable as a typeand others... so I am definitely doing something wrong.
Feel free to suggest a different approach to getModel(). This is just what I came up with but I might be ignoring a much simpler approach.
When I DID understand you correctly, you have different API-Calls which all return the same object. The only difference is, that the field "Data" can have different types.
Then you can simply change the type of data to object:
public object Data { get; set; }
And later simply cast this to the required object:
var data1=(Endpoint1[]) response.Data;
You're going to have a very tough time trying to dynamically create .NET types dynamically which requires advanced usage of Reflection.Emit. It's self-defeating trying to dynamically create Request DTOs with ServiceStack since the client and metadata services needs the concrete Types to be able to call the Service with a Typed API.
I can't really follow your example but my initial approach would be whether you can use a single Service (i.e. instead of trying to dynamically create multiple of them). Likewise with OrmLite if the Schema of the POCOs is the same, it sounds like you would be able to flatten your DataModel and use a single database table.
AutoQuery is an example of a feature which dynamically creates Service Implementations from just a concrete Request DTO, which is effectively the minimum Type you need.
So whilst it's highly recommended to have explict DTOs for each Service you can use inheritance to reuse the common properties, e.g:
[Route("/api/{ApiEndpoint}/1", "POST")]
public ApiRequest1 : ApiRequestBase<Endpoint1> {}
[Route("/api/{ApiEndpoint}/2", "POST")]
public ApiRequest2 : ApiRequestBase<Endpoint1> {}
public abstract class ApiRequestBase<T> : IReturn<ApiResponse<T>>
{
public int OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public string ApiEndpoint { get; set; }
}
And your Services can return the same generic Response DTO:
public class ApiResponse<T>
{
public T[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
I can't really understand the purpose of what you're trying to do so the API design is going to need modifications to suit your use-case.
You're going to have similar issues with OrmLite which is a Typed code-first POCO ORM where you're going to run into friction trying to use dynamic types which don't exist at Runtime where you'll likely have an easier time executing Dynamic SQL since it's far easier to generate a string than a .NET Type.
With that said GenericTableExpressions.cs shows an example of changing the Table Name that OrmLite saves a POCO to at runtime:
const string tableName = "Entity1";
using (var db = OpenDbConnection())
{
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "A"));
Assert.That(rows.Count, Is.EqualTo(1));
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "B"));
Assert.That(rows.Count, Is.EqualTo(1));
}
Which uses these extension methods:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef)
{
var hold = modelDef.Alias;
try
{
modelDef.Alias = table;
return fn();
}
finally
{
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table)
{
ExecWithAlias<T>(table, () => {
db.DropAndCreateTable<T>();
return null;
});
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false)
{
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, SqlExpression<T> expression)
{
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where)
{
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
But it's not an approach I'd take personally, if I absolutely needed (and I'm struggling to think of a valid use-case outside of table-based Multitenancy or sharding) to save the same schema in multiple tables I'd just be using inheritance again, e.g:
public class Table1 : TableBase {}
public class Table2 : TableBase {}
public class Table3 : TableBase {}
Im having some problems saving an object (FeatureType) that have a 1-M relationship with Section.
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("SectionId")]
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
If The ItemTypes are new i have no problem and the insert is done correctly.
But if i want to add some existing ItemTypes im getting this Error:
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker.
I have been reading about this problem but i havent found a way to solve it, and it might be because of how its designed my application.
Whem im mappinig from my viewModel to my Model, im getting the section ID and getting the section Object from my SectionRepository as this:
private Section GetSection()
{
var section = _sectionRepository.GetSection(SectionId);
return section;
}
And this is what is giving me the problem, as the section is now been tracked by the SectionRepository that have its own context.
How can i solve this? I have tried just creating a new section with the existing ID but it just create me an empty object.
private Section GetSection()
{
var section = new Section{Id=SectionId};
return section;
}
UPDATE
To save my entity i just use :
_repository.Create(featureType.ToModel());
public FeatureType ToModel()
{
var ft = new FeatureType
{
Name = Name,
ControlType = (ControlType)ControlType,
Order = Order,
Required = Required,
RequiredText = RequiredText,
ItemTypes = GetItemTypes().ToList(),
Section = GetSection(),
};
return ft;
}
UPDATE 2: This is how i have my repositories, i wouldn't like to manage any EF in my controller but with some kind of repository or service.
public class EFBaseRepository
{
protected MyContext Db = new MyContext();
public void Dispose(bool disposing)
{
Db.Dispose();
}
}
public class EFFeatureTypeRepository : EFBaseRepository, IFeatureTypeRepository
{
public IQueryable<FeatureType> GetFeatureTypes
{
get { return Db.FeatureTypes.Include("Section").Include("ItemTypes"); }
}
public Message Create(FeatureType feature)
{
try
{
Db.FeatureTypes.Add(feature);
Db.SaveChanges();
return new Message();
}
catch (Exception e)
{
throw;
// return new Message(e, string.Format("Error Creating {0}", feature.GetType()));
}
}
//..Other Methods
}
You say that the SectionRepository has its own context. That is going to cause you problems. The repositories should share a context. The context is a combination of the unit of work and repository patterns. You need to separate the two patterns:
How to migrate towards unit-of-work and repository pattern
EDIT
You can avoid having the DbContext in the Controller by implementing your own Unit Of Work pattern.
public interface IUnitOfWork : IDisposable
{
ISectionRepository SectionRepository {get;}
//etc
int Save();
}
then in your controller:
public ActionResult Create(FeatureTypeCreate featureType)
{
_Uow.SectionRepository.Create(featureType.ToModel());
_Uow.Save(); //Saving is the responsibility of the Unit Of Work
//not the Repository
}
More references:
Implementing the Repository and Unit of Work
Repository and Unit of Work in Entity Framework
John Papa's original source code
Simply, the error you're getting means that the entities were returned from a different instance of your DbContext than from which they are now trying to be saved. Make sure that you're not doing something like using two different usings around your repository and that your repository always makes use of the same DbContext per instantiation.
I am attempting to seed data for an MVC 4 project using SQL server 4.0 as the database engine, using the Microsoft MVC music store tutorial as an example. I have set up a seed and DB context models, but the controller is not able to find the data. I have verified that the the database file is created in App_Data and verified that SetIntitializer is correctly set up in Application_Start. Here is what I have for code:
Seed data:
namespace RationalMethodApp.Models
{
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
{
protected override void Seed(RationalMethodEntities context)
{
new List<Basin>
{
new Basin {
basinId = 1, // attempting to force a key value, will remove
Name = "Replace me with a real basin",
Location = "In a real location",
drainageArea = 0.0M
}
}.ForEach(b => context.Basins.Add(b));
Controller:
public ActionResult Index(int? bsnId)
{
if (bsnId == null) // here to force a key value, will change
bsnId = 1;
var basin = rmDb.Basins.Find(bsnId);
return View(basin);
}
The context class is:
namespace RationalMethodApp.Models
{
public class RationalMethodEntities : DbContext
{
public DbSet<Basin> Basins { get; set; }
public DbSet<SubArea> SubAreas { get; set; }
public DbSet<IdfCurve> IdfCurves { get; set; }
public DbSet<Analysis> Analyses { get; set; }
public DbSet<FlowSegment> FlowSegments { get; set; }
public DbSet<SheetFlowN> SheetFlowNs { get; set; }
public DbSet<RunoffCoefficient> RunoffCoefficients { get; set; }
public DbSet<StormFrequency> stormFrequencies { get; set; }
}
}
The debugger tells me that the "basin" object is still null in the controller after the .Find. This must be a simple, basic thing that I have overlooked, but all of the help I can find on-line assumes that the askers know what they are doing - not true in my case! I have also checked the discussion at Entity Framework database seed doesn't seed
but this does not seem to be the answer. Please bear with a total noob question.
You don't show the full code of you seed, so i can't really be sure, but you might be missing the Context.Changes().
As well you wrote
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
If you don't delete your database before the application start, it won't do anything as the db already exists.
You could use :
public class StartData : DropCreateDatabaseAlways <RationalMethodEntities>
to drop it every time you start or
public class StartData : DropCreateDatabaseAlways <DropCreateDatabaseIfModelChanges >
to drop db when Model changes (which is great for start of dev)
To debug: Drop your database, kill your application server (so it goes back to application start), breakpoint in your seed. Start Debug, if it goes in seed, check that data is in it after SaveChange().
public interface IPlugin
{
void Execute();
}
public class FirstPlugin : IPlugin
{
public string SomeSetting1 { get; set; }
public void Execute() { }
}
public class SecondPlugin : IPlugin
{
public string SomeSettingA { get; set; }
public string SomeSettingB { get; set; }
public string SomeSettingC { get; set; }
public void Execute() { }
}
I have a system that allows usesr to select one or more plugins. In the code above, I have an IPlugin interface that is implemented by many classes. Each class can have their own set of properties and each user can configure those properties.
For example, User A selects only the first plugin and configures SomeSetting1 to have a value of "ABC".
User B selects both plugins, but configures the first plugin's SomeSetting1 to have a value of "XYC".
public class User
{
public User(IPlugin[] plugins)
{
}
}
When I instantiate a user, I want to get a list of plugins that the user has configured and those plugins should be hydrated with what the user has configured.
However, I'm drawing a blank on how to design the database to be able to store information in this format. I could have a table:
User | Plugin
----------------
A | ...
B | ...
B | ...
... where the plugin column would be the serialized representation of the plugin that I can deserialize back into a class. However, that seems like a terrible/hacky idea. Is there a better way to do this?
If you don't have to query database by some of the properties serialized in Plugin column, I don't see it as a terrible/hacky idea. Also...you might consider using some non-schema database like mongodb. Anyway, I would do it with serializing (probably JSON object, if I will later consume that result from javascript, or some XML if that is more appropriate for your environment).
If you want to stay with more relational approach...then you will have a table with plugin properties...with columns: UserId, PluginId, PropertyName, PropertyValue...then, table with Plugins: PluginId, PluginName, and your table with users: UserId,...and some columns for users (this is just one way to design it) The problem is if you have some plugin properties that are complex objects...in that case, you will have to serialize them into PropertyValue column...
Tables
User
-----
UserID
Name
Plugin
------
PluginID
PluginName
PlugInProperty
------------------
PlugInPropertyId
PluginID
UserPlugin
------------
UserPluginId
UserId
PluginId
UserPlugInProperty
------------------
UserPluginId
PlugInPropertyId
Value