Automatically set added properties when retrieving database objects in C# - c#

I am extending a large C# project that connects to SQL Server.
In the database I have an Inventory table which has a foreign key manufacturer_id from the Manufacturer table.
I have added some properties to the Inventory class from the Manufacturer table because the app must continue to send Inventory objects but now include Manufacturer information as well.
public partial class Inventory
{
public string ManufacturerName {get; set;}
}
In my InventoryRepository I now call my SetManufacturerName method whenever I return Inventory objects and must remember to call it in any new methods.
Is there a way to call a method automatically whenever an Inventory object is retrieved from the database?
I am unable to change anything in the database.

You can call your desired method in the constructor of the class. It will ensure that whenever an instance of object is created your method is called
public partial class Inventory
{
public Inventory() { YourMethodCall(); }
public string ManufacturerName {get; set;}
}

You don't have to call anything upon object creation, just provide a non-trivial implementation of the property
public string ManufacturerName
{
get
{
// your code here,e.g.
return this.Manufacturer.Name;
}
...
}

Related

Is custom field option a Valueobject or an Entity in Domain Driven Design

I am using EF Core and I have a scenario where the user can create a custom field and then creates options for that custom fields.
public class CustomField : Entity<long>
{
[Required]
public string Name { get; private set; }
public bool IsRequired { get; private set; }
public List<CustomFieldOption> customFieldOptions;
public virtual IReadOnlyCollection<CustomFieldOption> CustomFieldOptions => customFieldOptions;
protected CustomField()
{
}
public CustomField(long id, string name, bool isRequired, List<CustomFieldOption> customFieldOptions)
{
Id = id;
Name = name;
IsRequired = isRequired;
this.customFieldOptions = customFieldOptions;
}
}
public class CustomFieldOption : Entity<long>
{
[Required]
[MaxLength(256)]
public string Text { get; private set; }
protected CustomFieldOption()
{
}
public CustomFieldOption(string text)
{
Text = text;
}
}
public class Client : Entity<long>
{
public Name Name { get; set; }
private List<ClientCustomFieldOptionValue> customFieldOptionValues { get; set; } = new List<ClientCustomFieldOptionValue>();
public IReadOnlyCollection<ClientCustomFieldOptionValue> CustomFieldOptionValues => customFieldOptionValues;
public Client(Name name)
{
}
public Result AddCustomFieldOptionValues(List<ClientCustomFieldOptionValue> values)
{
return Result.Success();
}
public Result RemoveCustomFieldOptionValues(List<ClientCustomFieldOptionValue> values)
{
return Result.Success();
}
}
public class ClientCustomFieldOptionValue
{
public CustomFieldOption CustomFieldOption { get; private set; }
protected CustomFieldOptionValue()
{
}
public ClientCustomFieldOptionValue(CustomFieldOption customFieldOption)
{
CustomFieldOption = customFieldOption;
}
}
CustomFieldOption seems to be a Value Object as the text it holds is something that doesn't need an Id. But then in terms of store persistency needs an Id to be stored in database on a different table where it can be queries by Id etc...
I am not sure if I shall add it as an Entity because ValueObjects do not have Id.
One other problem I have is validation. If it is an Entity how can I validate Text property. I know validation on constructor is a bad idea. If I validate it in the ApplicationLayer then wherever I create a new object I have to validate that is not empty and the length.
If I forget to add validation in one of the application services and pass null Text then I create an inconsistent state.
Update #1
A Client can select one or many options of a custom field. I suppose these needed to be stored on a separate table ClientCustomFieldOptionValue. In that case is this an entity or a valueobject? And what about CustomFieldOption. Does it become an Entity? I am quite confused when to use Entity or ValueObjects
Try not to think of persistency details while designing domain model.
According to your description, CustomFieldOption expresses an individual property with no business relations to any other structure, thus:
it should not hold a business identifier
it should encapsulate its own validations
Meaning it fits the concept of a value-object (validation inside ctor).
When it comes to persistency, your repository model should be capable of storing CustomFieldOption objects in a child table (with DB identifier) referencing the parent table (CustomField objects)
On the query side, repository should be capable of aggregating data from these two tables into a single CustomField entity.
(How exactly you implement such DB capabilities depends on the ORM you choose to work with, EF in your case)
Just one observation, if you will use Ef Core and the containing entity has a one to many relationship with the value objects, you will have this limitation:
Owned Entity types, Ef Core
Owned types need a primary key. If there are no good candidates properties on the .NET type, EF Core can try to create one. However, when owned types are defined through a collection, it isn't enough to just create a shadow property to act as both the foreign key into the owner and the primary key of the owned instance
If you are mapping your entities and value objects using DbContext, you usually define an owned entity type for a value object or use a record type.
For owned entities, this creates a column in your table like this: EntityName_ValueObject (i.e. Person_Address) but this works for a single value object not a collection when you don't know in advance the number of items in the collection.
It is correct that you should not concern with persistence when designing your domain, but is also correct to think that having a value object with an identity does not make sense.
Most important, you should be aware of this potential issue early on.

How to retrieve data from multiple tables and display in a view using viewmodel

I'm trying to develop a messeging system to my mvc application using mvc 5. I have tables called Event, EventUser, EventObject. Each of those tables have following;
Event
ID
CreatedBy
StartTime
IsShared
Budget
EventUser
EventID
UserID
IsAccepted
EventObject
EventID
ObjectID
in my messageController i have the index method which receive the parameter of the user id.i need to display every event that user has invited using this method..
namespace MvcApp.Controllers
{
public class MessageController : Controller
{
private EPlannerDatabaseEntities db = new EPlannerDatabaseEntities();
// GET: /Message/
public ActionResult Index(int UId)
{
/* linq expressions */
return View();
}
}
}
when the parameter has passed in, i want to;
*Select from EventUser table where UID=UserID and join the result with Event and EventObject tables by using EventID attribute.
*Finally by using the final result i need to display every event's infomation that user has invited; like CreatedBy , StartTime, Budget,other users,objects etc..
i'm new to mvc and viewmodel concept.I heard that viewmodel concept can help with these situations.can i overcome this problem by using viewmodel concept.if yes what are the things i need to add in view model?? otherwise what are the other ways to do this?
one way i can see of doing this is creating a custom return object and using EF to join all the tables together. Example
public class MyObject{
public DateTime DateCreated{get;set}
// add remaining properties here
// properties to get back
}
then in code you would use Entity Framework to create a joined data set into a nice list of objects. Example:
var results = (from b in bla join bla2 in (Some Second Query Here)
from SomeSecondQueryHere
where cond1 and cond2 Select new MyObject{
// add properties in here})
where you would replace the bla and bla2,etc with respective table names needed. Then all you need to do is
return View(results);
And the changes will be accessible in the View
If you question is regarding querying with an ORM like Entity Framework, you need to post your entities, not your table schemas. The whole purpose of an ORM is to abstract away the underlying database structure, so while the schema will often be similar to the entity class, it can also be quite different. As a result, I'll have to make assumptions about your entity classes.
To query everything, you just need something like the following:
var events = db.Events.Where(m =>
m.EventUsers.Any(u => u.UserID == UId && u.IsAccepted)
).Include(m => m.EventObjects);
That assumes entity classes along the lines of:
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public int UserID { get; set; }
public bool IsAccepted { get; set; }
}
You end up with an enumerable of Event. If you need to access the EventObjects for an individual event, you have to use the appropriate collection property. For example:
foreach (var item in events)
{
foreach (var obj in item.EventObjects)
{
// do something with `obj` (an invidual `EventObject` instance)
}
}
If you need the actual User object, you're better object querying that first and including related Events and EventObjects:
var user = db.Users.Include("EventUsers.Event.EventObjects").SingleOrDefault(m => m.UserID == UId);
That assumes entities like:
public class User
{
...
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public virtual Event Event { get; set; }
}
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
}
With that method, however, there's no way to filter the included Events by whether they're accepted or not. There's a potential way around that, but it requires disabling lazy-loading of EventUsers entirely and complicates querying the information you need. If you need to go that route, see: https://msdn.microsoft.com/en-us/data/jj574232.aspx#explicitFilter.
Otherwise, you can just exclude non-accepted events before iterating over the collection:
var events = user.EventUsers.Where(m => m.IsAccepted).Select(m => m.Event);
Really you don't need a view model, per se, for any of this. As you can either pass the lists of events (which will include any related EventObjects) or the the single user instance (which includes related events and related EventObjects) directly to your view.
A very high level description of how to solve your scenario using Entity Framework would be something like this:
First you've got to create a series of entity data objects that will represent your tables in the EF data model using EF Code first techniques.
Then you create DbContext objects with DbSets for your previously created entities.
Then you create at least one Service class that will have a property representing DbContext and a set of methods encapsulating Linq queries to your entities.
In the MVC controller you call an instance of Service that you previously create and assign it to a property ant Controller's construction time. Finally, in the Action method you should call the correct Service method and pass any result to the view.
( I am assuming this is a small Ad-Hoc system with a handful of tables , an elaborate System with production quality would require using IoC techniques).

Where do derived or inferred properties belong in an application?

I'm building an app using code first and generating the DB.
I can no longer modify the DB so, I can't add/change columns and tables. But the Domain Model (not sure if I'm using the term correctly) requires new properties (that are part of the domain) that can be inferred from the database data, but do not exist explicitly.
My database stores sales info for houses. So I have two tables, Houses and Sales. The tables are related by houseID. Now I want houses to have a property called LastSaleDate, but I can't change the underlying database.
So, How would I properly construct this new property and add it into the appropriate layer? Here is what my poco/entities look like. Just pseudo coded...
[I am trying to learn all I can about the tools and methods I use. I may be completely wrong on all my assumptions and maybe I am to add it to my pocos. If that is the case please explain how that would work]
[Table("HOUSE_TABLE")]
public class house {
//some properties
public int HouseID {get;set;}
}
[Table("SALE_TABLE")
public class sale {
//some properties
public int HouseID {get;set;
public int SaleID {get;set;}
public datetime SaleDate {get;set;}
public virtual House House {get;set;}
}
I almost feel like this would create 2 levels of mapping. Though, I don't believe I've ever seen this done in any code I've seen online.
poco -> AutoMapper?? -> entities -> Automapper -> viewModels
This logic most likely belongs on the Entity. Entities should have both data and behaviour. What you seem to be describing is some behaviour that is exposed as a property. So, you should add a property for the derived value to your entity. By default, if the property only has a getter, then EF will not try to map the value to the database.
For example:
[Table("HOUSE_TABLE")]
public class house
{
//some properties
public int HouseID {get;set;}
public virtual ICollection<Sale> Sales { get; set; }
public DateTime LastSaleDate
{
get
{
return this.Sales.OrderByDescending(s => s.SaleDate).First();
}
}
}

How to insert 2 new related DTOs using RIA Service?

I am using RIA Service in our Silverlight application. Database entities are not directly exposed to a client but I have a set of POCO classes for it. Then in CRUD methods for these POCO classes they are converted to database entities and saved to database.
The problem arises on the server side when client creates 2 new POCO entities which are related. Insert method is called on the server for each POCO entity separately and I may create corresponding new database entities there and add them to object context. But I see no way to add relation between these created database entities. Is there a solution for that?
For example, I have these 2 POCO entities (simplified):
[DataContract(IsReference = true)]
public partial class Process
{
[DataMember]
[Key]
public string Name
{
get; set;
}
[DataMember]
public long StepId
{
get; set;
}
[DataMember]
[Association("StepProcess", "StepId", "Id", IsForeignKey=true)]
public Step Step
{
get; set;
}
}
[DataContract(IsReference = true)]
public partial class Step
{
[DataMember]
[Key]
public long Id
{
get; set;
}
[DataMember]
public string Name
{
get; set;
}
}
And I have these 2 Insert methods in my domain service class:
public void InsertProcess(Process process)
{
var dbProcess = new DBProcess();
dbProcess.Name = process.Name;
//dbProcess.StepId = process.StepId; Cannot do that!
this.ObjectContext.AddToDBProcess(dbProcess);
}
public void InsertStep(Step step)
{
var dbStep = new DBStep();
dbStep.Name = step.Name;
this.ObjectContext.AddToDBSteps(dbStep);
this.ChangeSet.Associate<Step, DBStep>
(step, dbStep, (dto, entity) =>
{
dto.Id = entity.Id;
});
}
Client adds a new Process, then creates and adds a new Step to it and then calls SubmitChanges(). Process.StepId is not filled with a correct value as there is no correct Step.Id for the newly created step yet, so I cannot just copy this value to database entity.
So the question is how to recreate relations between newly created database entities the same as they are in newly created DTOs?
I know about Composition attribute but it is not suitable for us. Both Process and Step are independent entities (i.e. steps may exist without a process).
There are two ways to solve this:
Have each call return the primary key for the item after it is created, then you can store the resulting PKey in the other POCO to call the second service.
Create a Service method that takes both POCOs as parameters and does the work of relating them for you.
Thanks, although both these suggestions are valid but they are also applicable only for simple and small object hierarchies, not my case. I end up using approach similar to this. I.e. I have a POCO to database objects map. If both Process and Step are new, in InsertProcess method process.Step navigation property is filled with this new step (otherwise StepId can be used as it referenced to existing step). So if this process.Step is in the map I just fill corresponding navigation property in DBProcess, otherwise I create new instance of DBStep, put it to the map and then set it to DBProcess.Step navigation property. This new empty DBStep will be filled in InsertStep method later.

c# DAL class and business layer class

HI,
can you tell me if this is possible.
public class Person
{
public string Name { get; set; }
public int ID { get; set; }
}
Populate a class call say person which is in an assembly called Entities like this with the population of the code being done in a different assembly called DataAccessLayer (so person and the place where it is populated are not in the same assembly)
//the below code would be reading from a datareader etc but have just done this to make it //easy to explain.
Person p=new Person();
p.Name="tom";
p.id = 10;
The person class is now to be made accessible to another system to allow them to be able to access person. What i would like is to prevent the other system from being able to change the ID. be able to read it but not write. Do i need to create another class etc to allow this and only expose this class to the other system (i.e. a business object) (i.e. ORM)?
i know alot of people are going to say just make the ID readonly. i.e.
public int ID { get; }
but if i do this then i cannot populate the ID from the code similar to above because in my DataAccessLayer i will not be able to set the ID as it is readonly.
thanks
Niall
You can create an internal constructor for the object that you can pass ID into, then set the flag for the Entities DLL that allows another DLL (DataAccessLayer) to be able to see and use the internal calls within this DLL. (InternalsVisibleTo attribute)
Look toward ORM tools which will assign ID of entity for you and your id property will look:
public class MyEntity
{
public virtual int ID { get; protected set; }
// other properties
}
if you choose this way, you don't need to worry about assigning properties and casting of types.

Categories

Resources