Product Site Class Structure Suggestion - c#

I am creating a product website which have products and product categories, I have created the following classes:
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
}
public class DryFruitsPacks : Product
{
public string PackName { get; set; }
public decimal PackWeight { get; set; }
public decimal PackPrice { get; set; }
}
I want a method AddProduct(), which must be present in every class derived from product and adds that product to the database.

public class Product : IAddProduct
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public virtual void Add(Product p)
{
//Save to db
};
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
public override void Add(Product p)
{
//Save to db
}
}
public interface IAddProduct
{
void Add(Product product)
}
Public class SomeClass
{
Product product = new DryFruits()
{
ProductName = "Nut";
WeightInGrams = 0.01;
}
private IAddProduct _saveIt;
_saveIt.Add(product)
}
Public class SomeOtherClass
{
Product product = new Product()
{
ProductName = "Orange";
}
private IAddProduct _saveIt;
_saveIt.Add(product)
}
I always consider abstract classes to be a poor man's version of an interface. Even with the code above it fits the purpose of the SO's requirements.

You should add an abstract class to you base Product class. and override it in your derived classes.
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public abstract void Save();
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
public override void Save()
{
//save the product
}
}

Derived classes. When you create a derived class like DryFruits or DryFruitsPacks , you must provide an override method for all abstract methods in the abstract class. The AddProduct() method in both derived classes satisfies this requirement.
Override
Int field. An abstract class can have an instance field in it. The derived classes can access this field through the base syntax..
Int
Cannot instantiate abstract class. The important part of an abstract class is that you can never use it separately from a derived class.
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public abstract void AddProduct(params object[] arguments);
}
Abstract methods

Related

Multiple Entities with same properties repository pattern

I have a generic UOW repository pattern. I need to a add a few entities which will have the same properties but the names will differ from each other. Is there any easiest way to access the repositories without having to instantiate each and every entity repository separately.
Here is an example code of the entity structure.
public int Id { get; set; }
public string UserId { get; set; }
public int ProductId { get; set; }
public int OrderedQuantity { get; set; }
public int FreeQuantity { get; set; }
public double TotalPrice { get; set; }
public double DiscountOffered { get; set; }
public double TotalBilled { get; set; }
Entities can be like AbcProduct / XyzProduct / MnoProduct etc. they will be about 10-12 different entities of such products and cannot be kept under a single table with CategoryId. These tables will be often used and updated multiple times in the database which is why we would like to go with this approach.
Thanks in advance for the help.
You can make them share a common interface.
public interface IProduct
{
public int Id { get; set; }
public string UserId { get; set; }
public int ProductId { get; set; }
public int OrderedQuantity { get; set; }
public int FreeQuantity { get; set; }
public double TotalPrice { get; set; }
public double DiscountOffered { get; set; }
public double TotalBilled { get; set; }
}
As long as AbcProduct, XyzProduct and MnoProduct implement that interface, you can use a generic repository of that interface type
GenericRepository<IProduct> genericRepository;
var abcProduct = new AbcProduct();
var xyzProduct = new XyzProduct();
var mnoProduct = new MnoProduct();
genericRepository.Add(abcProduct);
genericRepository.Add(xyzProduct);
genericRepository.Add(mnoProduct);
Of course you can use inheritance. Use an abstract class as base class.
public abstract class Product
{
public abstract int Id { get; set; }
public abstract string UserId { get; set; }
public abstract int ProductId { get; set; }
public abstract int OrderedQuantity { get; set; }
public abstract int FreeQuantity { get; set; }
public abstract double TotalPrice { get; set; }
public abstract double DiscountOffered { get; set; }
public abstract double TotalBilled { get; set; }
}
and then derives other products
public class abcProduct:Product
{
public override int Id { get; set; }
...
}

Cannot implement property using derived class

public interface IBase
{
int Id { get; set; }
}
public interface IDerivedA : IBase
{
int Name { get; set; }
int Quantity { get; set; }
}
public interface IDerivedB : IBase
{
string Name { get; set; }
IEnumerable<IDerivedA> DerivedBs { get; set; }
}
And here is an implementation for a class which will be serialized, but I'm getting compilation error when I try to use DerivedASerialize class which is a derived class from IDerivedA interface
[MessagePack.Union(0, typeof(DerivedASerialize))]
[MessagePack.Union(1, typeof(DerivedBSerialize))]
[MessagePack.MessagePackObject(true)]
public class BaseSerialize : IBase
{
public int Id { get; set; }
public bool IsNull { get;set; }
}
[MessagePack.MessagePackObject(true)]
public class DerivedASerialize : BaseSerialize, IDerivedA
{
public int Name { get; set; }
public int Quantity { get; set; }
}
[MessagePack.MessagePackObject(true)]
public class DerivedBSerialize : BaseSerialize, IDerivedB
{
public string Name { get; set; }
public IEnumerable<DerivedASerialize> DerivedBs { get; set; }
}
Is there any work around? as I can only serialize classes.
And I would like to have another class which also derive from the same interface and have different properties
Using neuec's MessagePack.
Edit: Add serialization logic to classes.
If you require two different "Name" fields you can use explicit interface implementation:
public class DerivedBSerialize : BaseSerialize, IDerivedB
{
public string Name { get; set; }
public IEnumerable<DerivedASerialize> DerivedBs { get; set; }
string IDerivedB.Name { get; set; }
IEnumerable<IDerivedA> IDerivedB.DerivedBs { get; set; }
}
If you require just a single "Name" field - you can raise it to "IBase", or create another interface -
interface INameable { string Name {get; set;} }

How to declare List variable in abstract class

I am trying to write a basic abstract class where any class that extends it will have a List of some type.
The context is I call a web service, and I receive "pages" of orders, and each order has "pages" of order lines, etc.
abstract class Pagination
{
public int _offset { get; set; }
public int _total { get; set; }
public string previous { get; set; }
public string next { get; set; }
// Can I add something here that represents a list of items
// that is overridden in child classes somehow?
// public abstract List<Something?> items { get; set; }
// The purpose is for this generic "getItemCount" function or something similar
/*
public int getItemCount()
{
return items != null ? items.Count() : 0;
}
*/
}
class OrderHeader : Pagination
{
public int orderId { get; set; }
public List<OrderLine> items { get; set; }
}
class OrderLine : Pagination
{
public string sku { get; set; }
public int qty { get; set; }
public List<OrderLineDetails> items { get; set; }
}
class OrderLineDetails
{
public string serialNum { get; set; }
}
You can do that with generics
public abstract class Pagination<T>
{
public abstract List<T> Items { get; set; }
}
public class OrderHeader : Pagination<OrderLine>
{
public override List<OrderLine> Items { get; set; }
}
public class OrderLine : Pagination<OrderLineDetails>
{
public override List<OrderLineDetails> Items { get; set; }
}
You can use generics, e.g.:
abstract class Pagination<T>
{
// Other properties
public List<T> items { get; set; }
}
class OrderHeader : Pagination<OrderLine>
{
// Other properties
}
class OrderLine : Pagination<OrderLineDetails>
{
// Other properties
}
class OrderLineDetails
{
// Other properties
}
As addition to answers containing overriding I'll try to show slightly different approach which may broaden horizons. If you'll change your abstract class implementation you don't even need to override your Collection unless you need explicit implementation for get; or set; because you're specifying generic by inheritance itself
abstract class Pagination<T>
{
public virtual List<T> Items { get; set; }
}
class Tester : Pagination<string>
{
public void Test()
{
foreach (string item in this.Items)
{
// you have declared List<string> from Pagination<T>
}
}
}
Also this one may be useful for you: Generic Type in constructor
By that approach you would ended up with one base class which will provide you your generic List
abstract class Pagination2<T>
{
public string Property1 { get; set; }
public List<T> Items { get; set; }
public static Pagination2<T> GetInstance<T>()
{
Pagination2<T> instance = new Pagination2<T>()
{
Items = new List<T>()
};
return instance;
}
}
abstract class Pagination<T>
{
public int _offset { get; set; }
public int _total { get; set; }
public string previous { get; set; }
public string next { get; set; }
public List<T> items { get; set; }
public int getItemCount()
{
return items != null ? items.Count() : 0;
}
}
class OrderHeader : Pagination<OrderLine>
{
public int orderId { get; set; }
}
class OrderLine : Pagination<OrderLineDetails>
{
public string sku { get; set; }
public int qty { get; set; }
}

Using Generics with EF classes

I'm using EF6 with Code First and have a few tables with virtually the same schema. I would like to be able to perform queries on these tables and return the results to a common object (class) rather than creating a new one for each.
So for example, EF won't allow:
public class Product1 {
public int id { get; set; }
public string name { get; set; }
}
public DbSet<Product1> Products1 { get; set; }
public DbSet<Product1> Products2 { get; set; }
So I have to define a second POCO:
public class Product1 {
public int id { get; set; }
public string name { get; set; }
}
public class Product2 {
public int id { get; set; }
public string name { get; set; }
}
public DbSet<Product1> Products1 { get; set; }
public DbSet<Product2> Products2 { get; set; }
At least I would like to be able to treat results from these POCOs the same so that I can plug results into another class:
public class SomeClass {
public <Product1 or Product2> Product { get; set; }
}
Be able to store the result from either db table in the same object:
SomeClass someclass = new SomeClass();
someclass.Product = _context.Products1.Where(p => p.id == 1).First();
or
someclass.Product = _context.Products2.Where(p => p.id == 1).First();
int thisId = someclass.Product.id;
How do I make someclass.Product generic so that it will accept either Product1 or Product2?
You would have to make the classes inherit from an interface and then use that interface in a generic type constraint.
public interface IProduct
{
int id { get; set; }
string name { get; set; }
}
public class Product1 : IProduct
{
public int id { get; set; }
public string name { get; set; }
}
public class Product2 : IProduct
{
public int id { get; set; }
public string name { get; set; }
}
Then you could define SomeClass as follows:
public class SomeClass<TProduct> where TProduct : IProduct
{
public TProduct Product { get; set; }
}

Class property defined as an object that implements interface

I have a set of POCO classes which implement IConnectable and IEntity.
In one of the classes, Connection, I want two properties that are defined as objects that implement IConnectable.
public interface IConnectable
{
string Name { get; set; }
string Url { get; set; }
}
And my connection class
public partial class Connection : IEntity
{
public int Id { get; set; }
public T<IConnectable> From { get; set; }
public T<IConnectable> To { get; set; }
public ConnectionType Type { get; set; }
public double Affinity { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
I know I can't use generic objects are properties -- so is there any other way to do this?
It's most likely appropriate to just not have generics at all :
public partial class Connection : IEntity
{
public int Id { get; set; }
public IConnectable From { get; set; }
public IConnectable To { get; set; }
public ConnectionType Type { get; set; }
public double Affinity { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
If it's important that instances of Connection return types of something more derived then you'll need to make the whole class generic:
public partial class Connection<T> : IEntity
where T : IConnectable
{
public int Id { get; set; }
public T From { get; set; }
public T To { get; set; }
public ConnectionType Type { get; set; }
public double Affinity { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
If you need to be able to have two different IConnectable types for the two properties, then you need to generic parameters:
public partial class Connection<TFrom, TTo> : IEntity
where TFrom : IConnectable
where TTo : IConnectable
{
public int Id { get; set; }
public TFrom From { get; set; }
public TTo To { get; set; }
public ConnectionType Type { get; set; }
public double Affinity { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}

Categories