Creating common class objects based on class name and use it - c#

I have the same code logic used across different class objects.
For ex:
var matchingTypes = from matchType in order.Contacts
select matchType;
var matchingTypes = from matchType in customer.Contacts
select matchType;
Instead of writing duplicate lines of code, i would like to pass order, customer class names and get Contacts through it, so that the above code will look like (we are using LINQ in our code)
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
The stuff i tried is passed an object parameter
GetData(object objectElement) // method consuming an object parameter.
var objectOrder= objectElement as Orders;
var objectCustomer= objectElement as Customers;
if(objectOrder!=null)
{
objectElement = (Orders) objectOrder; //type
}
if(objectCustomer !=null)
{
objectElement = (Customers) objectCustomer;
}
By doing so, i am repeating my code, which i would like to avoid, any suggestions/ideas? thanks.
I would like to use objectElement and assign only once, so that i can call like this as shown below
var matchingTypes = from matchType in objectElement.Contacts
select matchType;

An interface would be the preferred way to do this, but you could also use dynamic to duck type a method:
public IEnumerable<Contact> GetContacts(dynamic yourObject)
{
return yourObject.Contacts;
}
Note this will not give you a compile error if you call it with something that doesn't have a property called Contacts of type IEnumerable<Contact> but will instead give you a runtime error.
Or you don't even actually need a method, you could just do this:
var matchedTypes = ((dynamic)yourObject).Contacts as IEnumerable<Contact>;
Interfaces would be a safer bet, but are a little tricky with generate entity framework classes. But you can do them becuase they are generated as partial classes. So you can do something like this:
public interface IHaveContacts
{
public IEnumerable<Contact> Contacts { get; }
}
and then:
public partial class Orders : IHaveContacts
{
// should need to do anything since the auto-genrated Contacts property
// will satisfy the interface
}
public partial class Customers : IHaveContacts
{
// ditto
}
And now you can do:
var matchedTypes = ((IHaveContacts)yourObject).Contacts;
Or, if you really, really must (which you don't):
var matchedTypes = from matchType in ((IHaveContacts)yourObject).Contacts
select matchType;

Create an interface IContactsContainer:
public interface IContactsContainer
{
public YourContactType Contacts{get;set;}
}
Then your customer and order classes can implement it:
public class Customers : IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
public class Orders: IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
After that in your method you can use:
IContactsContainer objectElement = yourOrderObject;

Related

How to return a different object depending on IF in C# (Generics)

I have an ASP.NET MVC (Not Core) project where I have run into some problems, and I think finally getting around to learning how to properly use generics could be a solution to my problems.
My case is that I have a SQL connection, that returns data and depending on the result of one field in the SQL, I want to use two different models. The models have a lot of properties in common so I thought the best practice would be to create a method that selects which of the models to create, fill in the differences, return the model and then continue to fill in the "common" properties.
I have tried to read a little on Generics but I am quite new to this so I haven't made any big strides.
My code example looks like this:
public ResultVM MainClass()
{
var resultData = new ResultVM();
// ... SQL returns data
while (reader.Read())
{
resultData.Add(reader);
}
return resultData;
}
public object CreateObject(SqlDataReader indata)
{
if((indata["Associate"].ToString()) == "0")
{
var individual = new Individual();
}
else
{
var group = new Group();
}
return object;
}
How can I dynamically (depending on the value of Associate field) create an individual or a group?
I suggest working directly with System.Type in your case. Here can be multiple more elegant solutions of your problem, depending of what you actually need:
indata.GetFieldType(int ordinal) will return the .NET type of your field
Serialize data with type handling, then you can simply get type after non generic deserialization. For example:
var result = JsonConvert.DeserializeObject(dataJson);
result will have Type of your actual object type. You can check it writing result.GetType() and create an object of this type. For more advanced use see Activator.CreateInstance(...)
For the most cases using interface is the best way:
interface ISomething
{
// ...
}
class Individual : ISomething
{
// ...
}
class Group : ISomething
{
// ...
}
Then you cat build your non generic method this way:
public ISomething CreateObject(SqlDataReader indata)
{
if((indata["Associate"].ToString()) == "0")
return new Individual();
else
return new Group();
}
Your generic object creation may look something like this:
public T CreateObject<T>(SqlDataReader indata)
{
var o = new T();
return o;
}
Where T is type, that you pass outside this method: CreateObject<YourType>(indata)
T can be any Type you want including Interfaces. Also working with generics you may want check types by using is keyword, but I recommend using interfaces and avoid is checks at all.
Example:
if(yourObject is YourType)
{
(yourObject as YourType).SomeSpecificToYourTypeMethod();
// ...
}
What about implementing an interface with all the common properties?
Something like
interface IInterface
{
string CommonProperty1 { get; set; }
string CommonProperty2 { get; set; }
}
class Individual : IInterface
{
// ...
}
class Group : IInterface
{
// ...
}
public IInterface CreateObject(SqlDataReader indata)
{
if((indata["Associate"].ToString()) == "0")
{
var individual = new Individual();
// ...
return individual;
}
else
{
var group = new Group();
// ...
return group;
}
}

c# - Initialize List<> from another class

I have defined a class which has List<>. I have shortened my Code. It is too large. There are too many List<>& in Method1() there is lots of code. Here is my code :-
public class Time : ITime
{
public List<Table1> Setts1 = new List<Table1>();
public List<Tabl2> Setts2 = new List<Table2>();
public void LoadSettings1(int companyId)
{
Setts1 = ctx.tblSett1.Where(a => a.CompanyId == companyId).Select(a => a).ToList();
}
public double Method1()
{
var data = Setts1.Where(m => m.SetType == "TYPE1").Select(m => m.Value1).FirstOrDefault();
......
......
}
}
I want to use Method1() in another class. My issue is Setts1 which is preloaded in the Time Class. So when it is used in within the Time class it has Records. But when i call it from another class obviously Setts1 will have no records. I tried to initialize it from another class like this :-
public class Class
{
.....
Time cls = new Time();
cls.Setts1 = ....;
cls.Method1();
}
But Setts1 shows no records when in Method1. How to initialize the List<> from another class?
Exposing field members of a class, outside of the class is not a good practice. So I recommend using properties like this:
//Mark the field member as private
private List<Table1> _Setts1 = new List<Table1>();
//Use Property to access the field outside of the class
public List<Table1> Setts1
{
get
{
if (_Setts1==null || _Setts1.Count()==0) //or any other logic you need
{
//Initialize the field memeber
_Setts1 = ctx.tblSett1.Where(a => a.CompanyId == companyId).Select(a => a).ToList();
}
return _Setts1
}
}
This way you can forget about methods like LoadSettings1 and it doesn't matter whether you use the Setts property inside the class or outside, it will be initialized at the right time.
You have to call 'LoadSettings1(int companyId)'. This is the method which brings the records and populates your 'List'.
public class Class
{
.....
Time cls = new Time();
cls.LoadSettings1(1);
cls.Setts1 = ....;
cls.Method1();
}
public class Something
{
private Time cls = new Time();
public Something(int companyId)
{
cls.LoadSettings1(companyId);
}
public void CallMethod1()
{
cls.Method1();
}
}
Something like this? Using constructor for your "other class" to LoadSettings.
cls.Setts1 = ....;
Actually I don't see how your code would not work, even if as Hossein said, it's bad practice. Look into how you're setting cls.Setts1 (the .... part). That's most probably the culprit

Nhibernate project into class property

How can I project into class property using NHibernate? For example:
[Test]
public void Test()
{
MyClass dto = null;
var test = CurrentSession.CreateCriteria<Contact>()
.Add(Restrictions.Eq("ContactName", "John Smith"))
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("ContactName").WithAlias(() => dto.SubClass.Name))
.Add(Projections.Property("EmailAddress").WithAlias(() => dto.Email))
)
.SetResultTransformer(Transformers.AliasToBean<MyClass>())
.List<MyClass>();
Assert.That(test[0].SubClass.Name, Is.EqualTo("John Smith"));
}
class MyClass
{
public string Email { get; set; }
public MySubClass SubClass { get; set; }
}
class MySubClass
{
public string Name { get; set; }
}
As you see I have a simple query and want to transform 1 row into 1 object - without lists but with a subclass. Unfortunately, it fails:
NHibernate.PropertyNotFoundException : Could not find a setter for property 'Name' in class 'MyTest+MyClass'
Is it possible to achieve this behaviour without custom transformer?
The default result transformer will be able to fill the root entity properties. But we can introduce our custom result transformer. There is one I do use:
DeepTransformer<TEntity> : IResultTransformer
Which is ready to convert . notation into chain of inner objects (excluding collections)
So, if you'll take it, and reuse it, this syntax would work:
...
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("ContactName").As("SubClass.Name"))
.Add(Projections.Property("EmailAddress").As("Email"))
)
.SetResultTransformer(DeepTransformer<MyClass>())
You can even improve it, but the idea of custom transformer should be clear now

Best Way To Filtering Child Entities In Entity Framework

I am not deleting entities. I just sign them by IsDeleted property. The problem is when I get a parent element, its all child elements are loaded even if IsDeleted propery is true or false. Then I did something like below, but I want to know is there a better way to do it ?
var result = from p in context.Set<Product>().Include(x => x.Reviews)
select new
{
Product = x,
ProductReviews = x.ProductReviews.Where(y => !y.IsDeleted)
};
var products = new List<Product>();
foreach (var product in result.OrderBy(x => x.Product.Id).Skip(skipRecords).Take(pageSize))
{
var p = new Product();
p = product.Product;
p.ProductReviews = product.ProductReviews.ToList();
products.Add(p);
}
return products;
How to improve this code block ?
Thanks
What I did to address this type of situation before was to create a specific interface signifying the classes that are "flag deleted" like this and then create an Extension Method that filters them out.
If you only have one class with the IsDeleted property, then you don't need a separate interface and you can just use the class instead. But I'll assume for the moment that you do have multiple classes and that the interface is needed.
So the interface would be defined like so:
public interface IHaveIsDeleted
{
public bool IsDeleted { get; set; }
}
Then my Extension Method would be defined in a static class like so:
public static class MyExtensionMethods
{
public IQueryable<T> FilterDeleted(this IQueryable<T> src) where T : IHaveIsDeleted
{
return src.Where(x => !x.IsDeleted);
}
}
Because this is done on an IQueryable<T>, the where clause gets built into the query that is sent to the database, so there won't be any records returned where IsDeleted is true. So all you would have to do in your example is call x.ProductReviews.FilterDeleted().
Now, the project that I was using this method in was actually using LINQ2SQL. And I'm rather new to EF myself, so there might be a more 'EF specific' way of doing this, (like perhaps some kind of Type Per Hierarchy construct, maybe?), but I just thought this would at least help make your queries simpler.
Hope that helps! ;)

Confuse with Generics and Entity Framework

I am new to c# and now bit confused with Generics and Entity Framework. I have two tables in database, which I retrieve in my code using Entity Framework. On my aspx page, I have a grid which should populate the data based on what table user selects.
In future there will be more tables. So I wanted to write a factory pattern to get the source list for datagrid. I can not make it to work because i am very confused.
Here is my code for BaseClass and two child classes.
static class Factory
{
public static ReportBase GetReport(string name)
{
switch (name)
{
case "Child1":
return new Child1();
case "Child2":
return new Child1();
default:
return null;
}
}
}
//Base Class
class ReportBase<T>
{
public List<T> _list;
public abstract void Load();
public abstract List<T> Filter(DateTime statrtDate, DateTime endDate);
}
//Child 1
class Child1 : ReportBase
{
public List<GetChild1> _list;
public Child1(){}
public override void Load()
{
//GetChild1 is the name of database table
var info = from p in Context.GetChild1 select p;
_list = info.ToList();
}
public List<GetChild1> Filter(DateTime startDate, DateTime endDate)
{
var filteredValues = from p in _list where p.UploadedDate <= startDate select p;
return filteredValues.ToList();
}
}
//Child 2
class Child2 : ReportBase
{
public List<GetChild2> _list;
public Child2() { }
public override void Load()
{
//GetChild2 is the name of database table
return (from p in Context.GetChild2 select p).ToList();
}
public List<GetChild2> Filter(DateTime startDate, DateTime endDate)
{
return (from p in _list where p.UploadedDate <= startDate select p).ToList();
}
}
Can Someone please correct the code accordingly? Do I have to use Generics here? I tried using it in BaseClass but it doesn't work properly, because I have to fix my child classes accordingly, for which I have no clue.
First of all, with generics you can write better code that is more readable and short.
I think it is better not to use a factory class for repositories in the end you need to know which type you are dealing with it in your code such as:
Child1 report = new Child1();
report.SomeBehaviorInChild1(); // this is not achievable with base class.
If you want to use this factory you can do the following:
ReportBase report = Factory.GetReport();
Secondly, it is a bad idea to let your list public because you don't want to those who are using your class to create a new list from their code such as:
report._list = new List();
You don't want this thing to happen to the objects in your class. So it is better to have your list private and depend only on the methods to return the data source of your report.
private List _list;
public List<T> GetDataSource()
{
return _list;
}
Thirdly, if you implement a generic reportbase you won't need to write the child classes unless they have something special that the base doesn't implement.
Fourthly, the current implementation of Filter method is soooo bad because what you are doing here is getting all the records from database then filtering them in memory. This implementation is a bad practice. A better approach is to use the IQueryable which is a deffered execution object i.e. the result won't be populated until you request it.
public List<GetChild1> FilterExample()
{
IQueryable<GetChild1> result = _context.GetChild1;
result = from p in result
where p.UploadDate < startDate;
select p;
//until this moment the query is still not send to the database.
result = result.OrderBy(p => p.UploadDate);
//when you call the ToList method the query will be executed on the database and the list of filtered and sorted items will be returned. Notice the sorting and filtering is done in the database which is faster than doing it in memory
List<GetChild1> populatedResult = result.ToList();
return populatedResult;
}
So this was a better approach to your problem. I think it is good for you to read a book called "More Effective C# 2008" it talks about queryable and linq in general.
Now if we apply this on your BaseReportClass we can get the following:
//Base Class
class ReportBase<T> where T: class
{
private DbContext _context;
public ReportBase(DbContext context)
{
_context = context;
}
//I think GetAll is a more suitable name for your method than load :D
public IQueryable<T> GetAll()
{
return _context.Set<T>();
}
public IQueryable<T> Filter(Func<T,bool> filterFunction)
{
var result = from p in GetAll()
where filterFunction(p)
select p;
return result;
}
}
Now to defining the additional behavior for the child classes.
//Child 1
class Child1 : ReportBase<GetChild1>
{
public ReportBase(DbContext context):base(context)
{
}
public List<GetChild1> FilterOnStartDate(DateTime startDate)
{
//I don't know if you are familiar with lambda expressions but if you are not you can research it on the internet.
//The parameter here is converted into a method that its parameter is "p" of type GetChild1
// and the body is "p.UploadDate < startDate".
// Note you can remove the type of the parameter because the compiler can predict it.
return Filter((GetChild1 p) => p.UploadDate < startDate).ToList();
}
}
This is the code that uses your classes:
Child1 report = new Child1(new GetChild1Entities());
report.FilterOnStartDate(DateTime.Now);
Hope this was useful.
Generics for defining how to display each entity type (or table) is the wrong approach.
Instead, using a pattern such as MVVM or MVC, where according to the type of the data (the model) you select a view.
MVVM
MVC
MVC for ASP.NET

Categories