How to change a class without re-coding? - c#

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.

Related

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?

C# Casting between objects of different types

First of all I'm new to C#.
The error I get is:
Additional information: Unable to cast object of type 'UserGUI.MyItems' to type 'CommonBookLib.AbstractItem'.
They are 2 different classes:
public class MyItems
{
public string ItemName { get; set; }
public int CopyNumber { get; set; }
public int Guid { get; set; }
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
}
and
public class AbstractItem : IPropsDetails
{
public int CopyNumber { get; }
public string ItemName { get; }
public DateTime Time { get; }
public int Guid { get; }
public AbstractItem(int copyNumber, string itemName, DateTime time, int guid)
{
this.CopyNumber = copyNumber;
this.ItemName = itemName;
this.Time = time;
this.Guid = guid;
}
}
It happens when I do:
AbstractItem myItemsList = (AbstractItem)LibraryList.SelectedItem;
logicManager.Remove(myItemsList);
Well, as you can see, I have MyItems which are responsible for the DataBindings in my GUI and AbstractItem which responsible for implementing an addition operation to where my data is saved.
Since I did not managed my code well I got into this situation and I really do not want to change MyItems (delete and recode AbstractItem).
How can I Convert the two?
By the way, I know AbstractItem has only 4 properties while MyItems has more.
However, I have children with the exact same properties of AbstractItem.
Any help would be appreciated. Thanks in advance!
Remove fields from the MyItems class that are also present in AbstractItem, and then have MyItems derive from it instead.
You'll have to add a constructor to MyItems that passes the required values to the base constructor, or add an empty constructor to the base class.
public class MyItems : AbstractItem
{
public MyItems(int copyNumber, string itemName, DateTime time, int guid)
:base(copyNumber, itemName, time, guid)
{
}
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
}
You can make MyItems inherit AbstractItem, or make a method that handle the conversion between them.
You seem to need a mapper more than a cast. Look at AutoMapper or write your own routine as suggested by habibhassani. Also, Grant's answer is very good.
But your question was about casting so here I show how you can implement a casting operator so that your cast would work. This is not a technique you should reach for lightly. It puts a dependency on AbstractItem directly in MyItems and it is not the most discoverable pattern for maintainers of your code.
public class MyItems
{
public string ItemName { get; set; }
public int CopyNumber { get; set; }
public int Guid { get; set; }
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
public static explicit operator AbstractItem(MyItems myitems)
{
return new AbstractItem(myitems.CopyNumber, myitems.ItemName, myitems.TimePrinted, myitems.Guid);
}
}
A couple more observances. Naming your class AbstractItem is confusing, it implies that it is actually abstract but it is not.
Guid is a poor name for a property because it is already a Type. You have something named Guid that is an int - confusing.

How to: Nested Lists in SQLite-Net Extensions

How to: Do nested lists in sqlite-net-extensions
Answer Found: Keeping the question as an example of how to do it.
The problem i encountered was not sqlite-net-extensions related, but i'm keeping the question for context.
[Old Question]
I've got a problem with TwinCoders SQLite-net extensions.
I'm trying to insert a Series object into my database:
I'm using the Db.InsertWithChildren(SelectedSeriesObject,recursive:true) method.
The Series object is added accordingly with it's attributes.
All the Episodes are added as well, no problems there.
The problem is the BaseSeason.
It will only insert one Season object, which is (for some reason) the last Season Object of the list of Seasons in the Series
public class BaseSeries : BaseMedia
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[Indexed]
public int ShowId { get; set; }
public string FirstAirDate { get; set; }
public string LastAirDate { get; set; }
public string Status { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseSeason> Seasons { get; set; }
/// <summary>
/// TvShow = 0, Anime = 1
/// </summary>
public int SeriesType { get; set; }
}
public class BaseSeason
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeries))]
public int SeasonId { get; set; }
public int SeasonNumber { get; set; }
public int NumberOfEpisodes { get; set; }
public string Plot { get; set; }
public string Poster { get; set; }
public string AirDate { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseEpisode> Episodes { get; set; }
[ManyToOne]
public BaseSeries BaseSeries { get; set; }
}
public class BaseEpisode
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeason))]
public int EpisodeId { get; set; }
public string Title { get; set; }
public string Plot { get; set; }
public string Poster { get; set; } //still path
public string AirDate { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string SeriesName { get; set; }
[ManyToOne]
public BaseSeason BaseSeason { get; set; }
}
Is there anyone with experience regarding nested relationships in sqlite-net-extensions that knows how to make this work or see what i did wrong?
So regarding writing nested lists in sqlite-net-extensions:
My problem turned out the be related to how I handle the creation of these objects, this is by no means related to sqlite-net extensions. So my bad!
Which means that the questions example is valid and works. (I tested it of course)
Setting up the entities for the database:
The example shown in my question, with a Series class, Season class and Episode class, is the correct way of setting it up.
Inserting into the database:
If you're wondering how to insert an object similar to my Series object (with nested lists), use:
db.InsertWitchChildren(yourObject, recursion: true)
Here's an extended example:
public void AddSeries()
{
MediaDB.db.CreateTable<BaseSeries>();
MediaDB.db.CreateTable<BaseSeason>();
MediaDB.db.CreateTable<BaseEpisode>();
MediaDB.db.InsertWithChildren(SelectedSeries, recursion: true);
}
Side Note:
The example uses a static property on class with the connection string. Like so:
public class MediaDB
{
public static SQLiteConnection db => new SQLiteConnection(new SQLitePlatformGeneric(),"Media.db");
}
Refrain from doing this it is not really the best thing to do, since you should use using for the SQLiteConnection, making sure it's disposed once you're done with it.
more info on: sqlite-net-extentions
[UPDATE]: Further expansion of handling nested lists in sqlite-net extensions:
Deleting tables with children:
This is quite simple, but i spent a good hour and half figuring it out anyways.
Just use:
For lists/arrays: db.DeleteAll(yourCollection, recursion: true)
For single objects: db.Delete(yourObject, true);
As an exmaple: here's my implementation of a method that will delete a List
(BaseSeries is the class shown in the original question question):
public static void RemoveCollection<T>(List<T> collection)
{
using (db)
{
if (typeof(T) == typeof(BaseMovie))
{
db.DeleteAll(collection);
}
if (typeof(T) == typeof(BaseSeries))
{
db.DeleteAll(collection, recursion: true);
}
}
}
The BaseMovie class is a simple single entity, recursion is not needed since it holds no children.

How to store and sort two types of classes in List<>?

I have two classes:
public class SavedQuote
{
public int ID { get; set; }
public string Text { get; set; }
public string Context { get; set; }
public string URL { get; set; }
public string Comment { get; set; }
public string WhereToSearch { get; set; }
public DateTime DateOfAdding { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class NoteOnSite
{
public int ID { get; set; }
public string URL { get; set; }
public DateTime DateOfAdding { get; set; }
public string OwnerName { get; set; }
public string Comment { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
I have also two lists: one that represents some "SavedQuotes" and one that has some "NoteOnSites". I need to sort data from those Lists by DateOfAdding and display them in one table on my webiste.
The problem is: I (probably) can't save objects with two different classes in one List<> (I need to do this to sort those objects). What do you advise me to do? How would you solve this problem?
I (probably) can't save objects with two different classes in one List<>
You can, as long as object have a common base class. In C#, all objects have a common base class System.Object, which is enough to store objects of entirely different types in a single list.
A heavyweight approach would be to put a common interface on the objects that you wish to sort:
public interface IWithDate {
public DateTime DateOfAdding { get; set; }
}
public class SavedQuote : IWithDate {
...
}
public class NoteOnSite : IWithDate {
...
}
...
var mixedList = new List<IWithDate>();
However, this may introduce more structure than you wish: making the classes related to each other through a common interface is too much, if all you need is to sort objects of these classes together.
If you wish to sort the objects on a commonly named property without adding any static structure around your classes, you can make a list of dynamic objects, and use DateOfAdding directly:
var mixedList = new List<dynamic>();
mixedList.AddRange(quotes);
mixedList.AddRange(notes);
mixedList.Sort((a, b)=>a.DateOfAdding.CompareTo(b.DateOfAdding));
Try a little Linq using JOIN
List<SavedQuote> savedQuotes = new List<SavedQuote>();
List<NoteOnSite> noteOnSites = new List<NoteOnSite>();
var results = from savedQuote in savedQuotes.OrderBy(x => x.DateOfAdding)
join noteOnSite in noteOnSites.OrderBy(x => x.DateOfAdding)
on savedQuote.ID equals noteOnSite.ID
select new { saved = savedQuotes, note = noteOnSites };​

Is possible to use generics in LINQ-to-SQL mapping?

Is there a way to define the following structure in a DataContext/DBML file?
public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
public EntitySet<IPermission> Permissions { get; set; }
}
public class User : IPermissionHolder
{
public int Id { get; set; }
public string Name { get; set; }
public EntitySet<Permission<User>> Permissions { get; set; }
}
public class Group : IPermissionHolder
{
public int Id { get; set; }
public string Name { get; set; }
public EntitySet<Permission<Group>> Permissions { get; set; }
}
public interface IPermissionHolder
{
int Id { get; set; }
}
public interface IPermission
{
Entity Entity { get; set; }
IPermissionHolder Holder { get; }
}
public class Permission<T> : IPermission where T : class, IPermissionHolder
{
public IPermissionHolder Holder
{
get { return PermissionHolder; }
}
public T PermissionHolder { get; set; }
public Entity Entity { get; set; }
}
If it's not possible, can you seggest another structure that fits my need?
Right now my DB is using two different tables for the GroupPermissions and the UserPermissions.
I don't like to have a common table where i have to add a "type" column... with two different table i have a much more strict control on the DB side.
Thanks for any help
P.S.: i'm still with the Framework 3.5, otherwise i could remove the IPermissionHolder interface and use co-variance
P.S.S.: asked also here, but no answer :(
http://social.msdn.microsoft.com/Forums/en/linqtosql/thread/04a03c68-79c0-4136-907c-f81440e78c45
EDIT:
i'm trying different things and i'm facing two main problems
1) I want to have a IEnumerable, but it will never works because i don't want only to get data, but also to push data and an object can not be covariant and contravariant at the same time.
So first of all i should choose: read or write.
2)Here the most difficult issue: how do i map TWO Association to a single property?
User:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name = "User_Permission", Storage = "permissions", ThisKey = "Id", OtherKey = "UserId")]
public EntitySet<Permission<User>> Permissions{ ... }
Group
[global::System.Data.Linq.Mapping.AssociationAttribute(Name = "Group_Permission", Storage = "permissions", ThisKey = "Id", OtherKey = "GroupId")]
public EntitySet<Permission<Group>> Permissions { ... }
Permission
[global::System.Data.Linq.Mapping.AssociationAttribute(Name = "???", Storage = "holder", ThisKey = "HolderId", OtherKey = "Id", IsForeignKey = true)]
public T PermissionHolder { ... }
Maybe i should call the Asscoiation "Holder_Permission"?!?
I tried with many different approach. I can say that with LINQ-TO-SQL is not possible to have generic mapping.
I will try with the Linq-To-Entity.

Categories