Reusing C# class in MVC C# - c#

I have an application that can contain a minimum of one "person" up to a maximum of fours "persons". I am using view models and manually mapping in the controller to the domain model.
I am completely lost as to how to include more than one "person" in the app. I've read up on using for but can't wrap my head around it.
Right now, I am just adding the data from the "person" class manually such that
Code:
public class SomeClass
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
... some more fields ...
}
and so on in the master class.
What I'd like to do is use a class such as:
Code:
public class Applicant
{
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
can be reused in another class multiple times.
How can I separate that to strip that and instead use a named class consisting of first, middle and last names and allowing up to four "person" instances in my master class?

Have you tried inheritance?
public class Person
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
and the Applicant class:
public class Applicant : Person
{
//Only extra properties and methods here.
public string FullName
{
get
{
return this.BorrowerFirst + " " + this.BorrowerMI + " " + this.BorrowerLast;
}
}
}
You can then have a vendor as well:
public class Vendor: Person
{
//Only extra properties and methods here.
}

Related

C# DTO List that consists of 2 other lists

Firstly, apologies if this seems basic, I am new to C#/dotnet and if the answer to this questions is somewhere obvious please point me in the right direction.
I have a DTO class with the following code
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonImagesListView> LessonImages { get; set; }
public List<LessonInstructionCardListView> InstructionCards { get; set; }
}
public class LessonImagesListView
{
public long Id { get; set; }
public string Title { get; set; }
public ImageDetailView Image { get; set; }
public LessonImagesListView()
{
Image = new ImageDetailView();
}
}
public class LessonInstructionCardListView
{
public long Id { get; set; }
public string Instructions { get; set; }
}
So I have 2 distinct types of object that I attach to the lesson and send to the frontend.
I will add that in the future I might have 6 different types of object.
These Images, or Instructions are also going to be displayed in a certain order on the front end so instead of sending them all separately I wanted to combine them all and send them in a new List LessonAssetsListView for example.
How can i create Lists in a DTO that combine 2 other lists ?
OR ... is this something I even need to do here ... and can i just do all this in my service.
Help appreciated.
You could simply define a type that composes both your existing and send a List of them
public class LessonAsset
{
public LessonImagesListView Image {get;set; }
public LessonInstructionCardListView Instruction {get;set;}
}
and then
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonAsset> LessonAssets { get; set; }
}

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

Adding Entity with child entities to Redis server resulting System.StackOverflowException

I am working on ASP.NET MVC project with EF6 with Database First. I am trying to use Redis server to cache frequently used objects.
But i am getting problem in saving related entities (parent-child). For example following Author and Author_Book classes are parent-child and referencing to each other (Foreign-Key constraint in RDBMS)
public partial class Author
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
public partial class Author_Book
{
public int Id { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public virtual Author Author { get; set; }
}
public partial class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
Querying and trying to store query result to Redis server as below
using (EFTestContext db = new EFTestContext())
{
var data = db.Authors.ToList();
redisClient.Set<List<Author>>("author", data);
}
Above line redisClient.Set.. resulting following Exception
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
However if i store Customer entity (which doesn't have child entities) into Redis server it work fine
using (EFTestContext db = new EFTestContext())
{
var customers = db.Customers.ToList();
redisClient.Set<List<Customer>>("customers", customers);
}
So my question is how to store complete entity (with childs) into redis server?
I followed [DataContract] / [DataMember] approach (As #oferzelig mentioned in comment). It is working fine and no longer raising that exception. I am describing it here so it could help someone else.
EF Database-first by default does not add [DataContract] / [DataMember] attributes, we need to modify T4 template for it. I did following modifications in Model template Model1.tt.
Added [DataContract] attribute before the line
<#=codeStringGenerator.EntityClassOpening(entity)#>
now it looks like
[DataContract]
<#=codeStringGenerator.EntityClassOpening(entity)#>
Added [DataMember] attribute before line
<#=codeStringGenerator.Property(edmProperty)#>
and it looks like
[DataMember]
<#=codeStringGenerator.Property(edmProperty)#>
We also need to generate [DataMember] attribute for one-to-many relationships (e.g. public virtual ICollection<Author_Book> Author_Book { get; set; } in question) but NOT for one-to-one (e.g. public virtual Author Author { get; set; } in question). To achieve it i added a new function in CodeStringGenerator class
public string NavigationProperty_NeedDataMember(NavigationProperty navProp)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0}",
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("[DataMember]") : ""
);
}
and called it just before the line
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
as below
<#=codeStringGenerator.NavigationProperty_NeedDataMember(navigationProperty)#>
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
And finally modified UsingDirectives procedure to add System.Runtime.Serialization, as below
public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
? string.Format(
CultureInfo.InvariantCulture,
"{0}using System;{1}" +
"{2}" +
"{3}",
inHeader ? Environment.NewLine : "",
includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
includeCollections ? (Environment.NewLine + "using System.Runtime.Serialization;") : "",
inHeader ? "" : Environment.NewLine)
: "";
}
That all.
Now it is generating following classes and i no need to edit classes manually after each update.
[DataContract]
public partial class Author
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
[DataContract]
public partial class Author_Book
{
[DataMember]
public int Id { get; set; }
[DataMember]
public int AuthorId { get; set; }
[DataMember]
public string Title { get; set; }
public virtual Author Author { get; set; }
}
Hope it will help someone else.

View Model implementation - less fields than in entities

I have two entities: Person and Quote (in one to many relationship)
Person:
public class Person
{
public int PersonID { get; set; }
[Required]
[StringLength(20]
public string Name { get; set; }
[StringLength(30]
public string Relation { get; set; }
public byte[] Image { get; set; }
[StringLength(50)]
public string ImageMimeType { get; set; }
public virtual ICollection<Quote> Quotes { get; set; }
}
Quote:
public class Quote
{
public int QuoteID { get; set; }
public int PersonID { get; set; }
[Required]
[StringLength(200)]
public string QuoteName { get; set; }
[StringLength(400)]
public string Context { get; set; }
public DateTime? Date { get; set; }
public virtual Person Person { get; set; }
}
I want to make a ViewModel for displaying quotes in short format - I need just a few properties - Person Name, QuoteName and Person Image. I could do something casual like they're showing in every ASP.NET MVC tutorial:
public class QuoteViewModel
{
public IEnumerable<Quote> Quotes { get; set; }
}
Is there a better way rather than creating IEnumerable with type of Quote and loading all properties?
How about creating QuoteShort model and making QuoteViewModel as IEnumerable<QuoteShort> QuotesShort.
In controller I would map every 3 fields from repository to QuoteShort and add it to QuotesShort IEnumerable (even though I don't know how to persist them to QuotesShort IEnumerable )
Some examples appreciated.
You can make a QuoteShort ViewModel with just the few properties you need, and then have your view expect IEnumerable<QuoteShort> as its model. You don't necessarily have to wrap that up in another container.
If you have this:
public class QuoteShort{
public Person Person {get;set;}
public string Name {get; set;}
// etc
}
You can do this in the controller:
var quotes = //however you get your list of quotes
var model = (from q in quotes select new QuoteShort
{ Person = q.Person, Name = q.Name /*etc*/ }).ToList();
return View(model);
What about something like
public class QuotesShortViewModel
{
public IEnumerable<QuoteShortViewModel> QuotesShort { get; set; }
}
public class QuoteShortViewModel
{
// ... the properties you need
}
Create a View that receives a QuotesShortViewModel and iterates through the list, rendering the short quotes as it pleases you.
AutoMapper is useful to map between Models and ViewModels in your controllers.

How to change a class without re-coding?

I am creating a drivers license object in my project, that employees will all have one of their own linked to their unique clock number. I have a separate table in my database for the driving license but in the future more types of vehicles will need to be added, is there anyway to do this without re-coding?
the columns in my database are the same as the attributes for the class below
public class LicenseDTO
{
public int ClockNo { get; set; }
public bool CBalance { get; set; }
public bool MR16 { get; set; }
public bool OrderPicker { get; set; }
public bool Reach { get; set; }
public bool Pedestrian { get; set; }
public bool Lorry { get; set; }
public bool Sweeper { get; set; }
public bool Washer { get; set; }
}
EDIT
I have tried to create this the best I could but I feel like it's really long winded and can be done a more efficient way. Here's an updated version of my code.
public class LicenseDTO
{
public int ClockNo { get; set; }
public List<Common.VehicleTypeDTO> Vehicles { get; set; }
}
public class VehicleTypeDTO
{
public string VehicleType { get; set; }
public bool Allowed { get; set; }
}
private void btnClockCardIn_Click(object sender, EventArgs e)
{
Common.LicenseDTO License = new Common.LicenseDTO();
List<Common.VehicleTypeDTO> Vehicles = new List<Common.VehicleTypeDTO>();
Common.VehicleTypeDTO CBalance = new Common.VehicleTypeDTO();
Common.VehicleTypeDTO MR16 = new Common.VehicleTypeDTO();
License.Vehicles = Vehicles;
CBalance.VehicleType = "CBalance";
CBalance.Allowed = true;
MR16.VehicleType = "MR16";
MR16.Allowed = false;
License.Vehicles.Add(CBalance);
License.Vehicles.Add(MR16);
foreach (Common.VehicleTypeDTO Vehicle in License.Vehicles)
{
MessageBox.Show(Vehicle.VehicleType + " " + Vehicle.Allowed);
}
}
Why not to create a table with the types of vehicles? In the future you can access to your table and insert more types.
public class VehicleTypeDTO
{
public int Id{ get; set; }
public string Name{ get; set; }
}
public class LicenseDTO
{
public int Id { get; set; }
public List<VehicleTypeDTO> VehicleTypes { get; set; }
}
You should have made an entity LicenseDTO with the attributes ClockNo and CBalance alongside an array of the type Vehicle. which will be an interface. the interface Vehicle can define any common methods the vehicles have. and all future vehicles will have to implement the interface. that way you dont have to change any code. Your current code cannot be "changed" without editing. You could try to extend your LicenseDTO class with another entityclass which implements the above interface. but there isnt much more you can do without editing.
If you want maintainability use interfaces, repository patterns, abstract classes and dependency injection to start with.
Instead of having multiple bit columns in your database to indicate different types of vehicles, have a single VehicleType table. Then you can add as many different vehicle types as you like and use the VehicleTypeID to uniquely identify them. You can then add more and more vehicle types to the table without having to write more code.
VehicleType
VehicleTypeID int
VehicleTypeName varchar(50)
public class LicenseDTO
{
public int ClockNo { get; set; }
public int VehicleTypeID { get; set; }
}
If you want to have multiple types of vehicles against a single ClockNo then use a list of int:
public class LicenseDTO
{
public int ClockNo { get; set; }
public List<int> VehicleTypes { get; set; }
}
Alternately you could have a reference to the VehicleType objects instead of just the ID's.

Categories