Problem on using containers within models C# - c#

I try to use models to get my containers on stored procedure executions , but it says that SP on SP.GR0007R, which is variable of the models, is a variable but used like a type, but if i use Cont.ReportManager.GR0007R instead, no errors found but no result either.
This is my code:
using (var db = new SqlConnection(connStr))
{
var param = new DynamicParameters();
switch (filter.RPTCode)
{
case "GR0007R":
param.Add("#Name", !string.IsNullOrEmpty(filter.NAME) ? filter.NAME : string.Empty);
var sp7r = await db.QueryAsync<SP.GR0007R>(filter.RPTQuery, param, commandType: CommandType.StoredProcedure);
break;
}
res = true;
}
this is where i declare SP
public async Task<bool> GetReportData(Models.ReportManager.EswisReportModel SP, GetListParameterReportList filter)
and this is my model
public class EswisReportModel
{
public Cont.ReportManager.GR0001R GR0001R { get; set; }
public Cont.ReportManager.GR0002R GR0002R { get; set; }
public Cont.ReportManager.GR0007R GR0007R { get; set; }
public Cont.ReportManager.GR0008R GR0008R { get; set; }
public Cont.ReportManager.GR0009R GR0009R { get; set; }
}
so do i have to convert it or there's other way to call it?
thank you

It seems you are trying to put in an instance and property name, and hope that the generic handling will be so smart to know you mean the backing type of that property. It doesn't. According to the C# specification, you need to use the type name, not a reference to it, nor some kind of inferred use of it through a variable name.
So that is why you should use the actual type name, Cont.ReportManager.GR0007R:
var sp7r = await db.QueryAsync<Cont.ReportManager.GR0007R>(...);

Related

DDD modelling of articles, variants and their parameters

I am learning DDD and trying to model articles, its variants and parameters.
Article can be on it's own without variants
Variant must be child of an article
both article and variant can have some parameters (colors, brands, sizes...), physical quantities (width, length, some article-specific like inner length)
If you set some parameter on an article, it can be "synchronized" to it's children variants
you can override this in a variant by setting that parameter as "unlinked", then this variant would have different parameter value than article
some parameters can be set multiple times (color: red, blue), but some only once (brand)
those parameters are dynamically create, it's not a Color or Brand property but key-value selected from preconfigured values
I think my main aggregate roots will be Article and Variant.
My current code looks like this:
internal class Article : AggregateRoot<ArticleId>
{
private readonly ISet<VariantId> _variants = new HashSet<VariantId>();
private readonly ISet<AssignedParameter> _parameters = new HashSet<AssignedParameter>();
private readonly ISet<AssignedPhysicalQuantity> _physicalQuantities = new HashSet<AssignedPhysicalQuantity>();
public string Name { get; private set; }
public string Catalog { get; private set; }
public IReadOnlySet<VariantId> Variants => _variants.AsReadOnly();
public IReadOnlySet<AssignedParameter> Parameters => _parameters.AsReadOnly();
public IReadOnlySet<AssignedPhysicalQuantity> PhysicalQuantities => _physicalQuantities.AsReadOnly();
private Article(ArticleId id, string name, string catalog)
: base(id)
{
Name = name;
Catalog = catalog;
}
public static Article Register(ArticleId id, string name, string catalog)
{
var article = new Article(id, name, catalog);
article.AddEvent(new ArticleRegistered(article.Id, article.Name, article.Catalog));
return article;
}
public void AssignParameter(Parameter parameter, ParameterValue parameterValue, bool syncToVariants)
{
if (!parameter.CanBeAssignedMultipleTimes && _parameters.Any(p => p.ParameterId == parameter.Id))
{
throw new ParameterCanBeAssignedOnlyOnceException($"Parameter {parameter.Id} can by assigned only once.");
}
var assignedParameter = new AssignedParameter(parameter.Id, parameterValue.Id, syncToVariants);
if (!_parameters.Add(assignedParameter))
{
throw new ParameterIsAlreadyAssignedException($"Parameter {parameter.Id} with value {parameterValue.Id} is already assigned.");
}
AddEvent(new ArticleParameterAssigned(Id, assignedParameter.ParameterId, assignedParameter.ParameterValueId));
}
public void UnassignParameter(Parameter parameter, ParameterValue parameterValue)
{
var assignedParameter = _parameters.FirstOrDefault(p => p.ParameterId == parameter.Id && p.ParameterValueId == parameterValue.Id);
if (assignedParameter is null)
{
throw new ParameterIsNotAssignedException($"Parameter {parameter.Id} is not assigned.");
}
_parameters.Remove(assignedParameter);
AddEvent(new ArticleParameterUnassigned(Id, assignedParameter.ParameterId, assignedParameter.ParameterValueId));
}
// physical quantity assign / unassign are similar to parameters
}
internal class Variant : AggregateRoot<VariantId>
{
private readonly ISet<AssignedParameter> _parameters = new HashSet<AssignedParameter>();
private readonly ISet<AssignedPhysicalQuantity> _physicalQuantities = new HashSet<AssignedPhysicalQuantity>();
public string Name { get; private set; }
public string Catalog { get; private set; }
public EanCode Ean { get; private set; }
public decimal Weight { get; private set; }
public IReadOnlySet<AssignedParameter> Parameters => _parameters.AsReadOnly();
public IReadOnlySet<AssignedPhysicalQuantity> PhysicalQuantities => _physicalQuantities.AsReadOnly();
internal Variant(VariantId id, string name, string catalog, EanCode ean, decimal weight)
: base(id)
{
Name = name;
Catalog = catalog;
Ean = ean;
Weight = weight;
}
// parameter and physical quantity assignment methods
}
Parameters:
internal class Parameter : AggregateRoot<ParameterId>
{
private readonly ISet<ParameterValue> _values = new HashSet<ParameterValue>();
public string Code { get; private set; }
public string Name { get; private set; }
public bool CanBeAssignedMultipleTimes { get; private set; }
public IReadOnlySet<ParameterValue> Values => _values.AsReadOnly();
public Parameter(ParameterId id, string code, string name, bool canBeAssignedMultipleTimes)
: base(id)
{
Code = code;
Name = name;
CanBeAssignedMultipleTimes = canBeAssignedMultipleTimes;
}
}
internal class ParameterValue : Entity<ParameterValueId>
{
public string Code { get; private set; }
public string Name { get; private set; }
public Parameter Parameter { get; private init; } = null!;
public ParameterValue(ParameterValueId id, string code, string name)
: base(id)
{
Code = code;
Name = name;
}
}
Value objects:
// for Article, variant doesn't have SyncToVariants property and has some other
internal class AssignedParameter : ValueObject
{
public ParameterId ParameterId { get; private init; }
public ParameterValueId ParameterValueId { get; private init; }
public bool SyncToVariants { get; private init; }
public AssignedParameter(ParameterId parameterId, ParameterValueId parameterValueId, bool syncToVariants)
{
ParameterId = parameterId;
ParameterValueId = parameterValueId;
SyncToVariants = syncToVariants;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return ParameterId;
yield return ParameterValueId;
}
}
internal class AssignedPhysicalQuantity : ValueObject { ... }
My questions:
What would be the best way to notify variants of the parameter change? I can think of two ways using events.
First would be using ArticleParameterChanged(ArticleId, parameter.Id, parameterValue.Id). I would handle this event and changed all variants at once in the handler - I don't think this is the way, but I wouldn't need to hold variants collection in article.
Second would be to loop through variant IDs and create ArticleVariantParameterChanged(ArticleId, VariantId, parameterId, parameterValueId) event. This seems more correct to me?
if (syncToVariants)
{
foreach (var variantId in _variants)
{
AddEvent(new ArticleVariantParameterChanged(Id, variantId, parameter.Id, parameterValue.Id);
}
}
How do I add new variant to article? The easiest way would be to create new variant and update the article in one transaction.
// Article method
public Variant RegisterVariant(VariantId variantId, ...)
{
var variant = new Variant(variantId, ...);
_variants.Add(variantId);
return variant;
}
// command handler? or domain service?
var article = await _articleRepo.GetAsync(articleId);
var variant = article.RegisterVariant(variantId, ...);
await _variantRepo.AddAsync(variant);
await _articleRepo.UpdateAsync(article);
Or using events?
// Article method
public Variant RegisterVariant(VariantId variantId, ...)
{
var variant = Variant.Register(variantId, this.Id, ...);
return variant;
}
// Variant static method
public Variant Register(VariantId variantId, ArticleId articleId, ...)
{
var variant = new Variant(variantId, articleId, ...);
variant.AddEvent(new VariantRegistered(variantId, articleId));
return variant;
}
// command handler
var variant = article.RegisterVariant(...);
await _variantRepo.AddAsync(variant);
// VariantRegisteredHandler
article.AddVariant(variantId);
However here it seems kind of confusing to me, article.RegisterVariant and article.AddVariant... Maybe it's just wrong naming?
Also here can occur condition race between adding new variant and assigning a new parameter, when someone adds new parameter before the VariantRegistered event was handled, so it wouldn't sync that parameter.
So I'm thinking, is it even good idea to store those shared parameters in each variant? Maybe it would be enough to just have variant specific parameters there and merge everything in the read model? However this would be harder to prevent duplications - if the article already has a parameter "color - red", assigning "color - red" to variant would need to check the article parameters too and there can be another race condition.
I read that entities without any domain business logic could be treated as CRUD, that means they wouldn't even inherit AggregateRoot and each of them would have own repository, right?
Let's say someone really wants to delete some parameter value, for example blue color. This wouldn't (hopefully) happen in my app, but I'm still curious how this would be handled. He confirms he really wants to delete it and I need to go through all articles and unassign it from them. How?
My idea would be either to have ParameterValueDeleted event and ParameterValueDeletedHandler would query for all articles and variants and unassign it one by one, this handler would take really long time to execute.
Or ParameterValueDeletedHandler would query for all IDs, create some event for them and that handler would unassign it later. However in the latter case I don't know how that event would be named to make sense. UnassignArticleParameter seems more like command than event and ArticleParameterUnassigned is something coming from article. Also I read that commands indicate something that can be rejected, so I would say command doesn't fit here.
Also I see a problem when someone deletes that parameter and someone else queries for an article which doesn't have it unassigned yet - database join would fail because it would join to non existent parameter (considering single database for read and write model).
If I wanted to have mandatory parameters, where would be the best place to validate that all of them are set? Move the article registration logic to ArticleFactory and check it there? And for variants maybe ArticleService or VariantFactory? This seems kinda inconsistent to me, but maybe it's right?
var article = await _articleRepo.GetAsync(articleId);
_articleService.RegisterVariant(article, /* variant creation data */);
_variantFactory.Register(article, /* variant creation data */);
I think this should be all, I hope I explained everything well.
I would appreciate any help with this!

How to map a property in C# that is a list?

These are my classes:
public class Registration
{
public bool? IsRegistered { get; set; }
public List<RegistrationProcess> RegistrationProcess { get; set; }
}
public class RegistrationProcess
{
public bool? PaidInFull { get; set; }
public double PaymentAmount { get; set; }
public bool IdentityVerified { get; set; }
}
I have a method that is doing the object mapping like this:
public Registration Translate(Services.Registration source)
{
return new Registration
{
IsRegistered = source.IsRegistered,
RegistrationProcess = new List<RegistrationProcess>
{
new RegistrationProcess()
{
PaidInFull = source.RegistrationProcess.Select(o => o.HasPaid),
}
}
};
}
I am not sure how to set up the mapping for the RegistrationProcess.
I want to map PaidInFull within RegistrationProcess to the property HasPaid. They are both bools.
I am getting an error: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<bool?>' to 'bool?'
I feel like I need to add something to the end of the Select statement but I am not sure what. I did FirstOrDefault() and that made the error go away but I only got one value back and that is not what I want.
The problem with your approach is that you are only creating one instance of RegistrationProcess inside the list constructor. So by calling source.RegistrationProcess.Select(o => o.HasPaid) and assign it to your newly created RegistrationProcess you are creating a Collection of all bool values of your service registration process and try to assign it to a single registration process.
The Solution is to create multiple RegistrationProcess instances. In fact, one for each element in source.RegistrationProcess. To do this you can use the Select method on source.RegistrationProcess directly:
source.RegistrationProcesses.Select(x => new RegistrationProcess() { PaidInFull = x.HasPaid }).ToList()
As you can see, for every element in source.RegistrationProcesses a new RegistrationProcess is created. Or in other words: you select the elements of source.RegistrationProcesses as new RegistrationProcess() { PaidInFull = x.HasPaid } if that makes more sense to you.
The .ToList() converts the IEnumerable to a list.

Get specific type from derived class

Brief: I'm creating an MVC application in which I need to display a variety of types documents, some containing more author information than others.
What I wanna do: My approach is to have a generic "view document" view, which dynamically displays the document in a format dictated by the shape/type of the object passed to it.
Example: A simple document would be loaded into a SimpleDocumentViewModel, and display as such. However I'd like to load a larger type of document into an ExtendedDocumentViewModel, bringing with it additional information about both the document and the author. The view(s) would then display the appropriate data based on the object it receives.
Where I'm at now: In this vein I've created the following interfaces and classes, but I'm stuck as to how to return/identify the more specific return types in their derived classes.
abstract class BaseDocumentViewModel : DocumentViewModel, IDocumentViewModel
{
public int DocumentId { get; set; }
public string Body { get; set; }
public IAuthorViewModel Author { get; set; }
}
class SimpleDocumentViewModel : BaseDocumentViewModel
{
}
class ExtendedDocumentViewModel : BaseDocumentViewModel
{
public new IAuthorExtendedViewModel Author { get; set; }
}
interface IAuthorViewModel
{
int PersonId { get; set; }
string Name { get; set; }
}
interface IAuthorExtendedViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
}
Question: So my question is; how best can I get the specific types from the fully implemented classes, or do I need to return the base types and query it all in the view? Or am I off my head and need to go back to the drawing board?
Edits:
I know that c# doesn't support return type covarience, but hoped that there may be another way of returning/identifying the derived types so that I don't have to query them all in the view.
My current solution would be to always return the base types, and have a separate view for each concrete type that simply casts each object to the correct type, only querying those that could differ. Perhaps this is the best solution end of, but it feels very inelegant.
Usually you can do a simple "is" check. So you can have conditional rendering in your views, for example:
#if(Model is ExtendedDocumentViewModel)
{
// render ExtendedDocumentViewModel html here
}
Type checking is usually considered an anti pattern, however I am not sure if there is a much better approach to this problem. If you are using .NET Core you can also check the subclass tag here http://examples.aspnetcore.mvc-controls.com/InputExamples/SubClass .
Possible cleaner option is to just have a signature in the interface called GetView that each document has to implement. This way each document type has their own way of implementing the function and the calling function knows that each document has a function GetView. This method will work well if every document has a unique way of viewing the document. However if some documents share the same way of getting views, then may I suggest creating each View type into their own class and you can assign the views types to each document. I suggest looking into the strategy pattern.
First suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
view GetView()
{
... do document specific stuff
... return view
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
view GetView()
{
... do document specific stuff
... return view
}
}
interface IAuthorViewModel
{
view GetView();
}
Second suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
public viewType1 view {get;set;}
public SimpleDocumentViewModel(viewType1 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView();
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
public viewType2 view {get;set;}
public ExtendedDocumentViewModel(viewType2 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView(ExtraData,MoreExtraData);
}
}
interface IAuthorViewModel
{
view GetView();
}
I may be way off base here, but as I understand your question... why not just throw the return types in an object and pass that to your view?
You could look at the desired method and use reflection to pull out whatever info you want. Modify this and the object class hold whatever you want it to.
public class DiscoverInternalClass
{
public List<InternalClassObject> FindClassMethods(Type type)
{
List<InternalClassObject> MethodList = new List<InternalClassObject>();
MethodInfo[] methodInfo = type.GetMethods();
foreach (MethodInfo m in methodInfo)
{
List<string> propTypeList = new List<string>();
List<string> propNameList = new List<string>();
string returntype = m.ReturnType.ToString();
foreach (var x in m.GetParameters())
{
propTypeList.Add(x.ParameterType.Name);
propNameList.Add(x.Name);
}
InternalClassObject ICO = new InternalClassObject(c.Name, propNameList, propTypeList);
MethodList.Add(ICO);
}
return MethodList;
}
}
he object class could be something like this or modify it however you want:
public class InternalClassObject
{
public string Name { get; set; }
public List<string> ParameterNameList { get; set; }
public List<string> ParameterList { get; set; }
public InternalClassObject(string iName,List<string> iParameterNameList, List<string> iParameterList)
{
Name = iName;
ParameterNameList = iParameterNameList;
ParameterList = iParameterList;
}
}
You could call the method like this with the desired class.
public static List<InternalClassObject> MethodList = new List<InternalClassObject>();
DiscoverInternalClass newDiscover= new DiscoverInternalClass();
MethodList = newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
Now you can have your GetView build based on what is in MethodList
Hope this helps!

Moving app.config settings to db and using value type to dynamically set the return data type

I have a windows service application that I want to manage setting for from a asp.net site. As my application has grown, my list of settings in the app.config file has grown as well. So, I have decided to move these setting to a table in my SQLDB to be able to track them and give me a way to modify the settings from the admin site. I ran into an issue where I am trying to store the setting value type in the table and then use it to change the value property to the type stored. For instance I have quite a few TimeSpan defined. In the SQL table the data would look like this.
guid settingName settingValue settingType
936767f5-63b5-4844-9991-29f6f92c53f2 SMTimeStart 12:00:00 TimeSpan
Im trying to use the following code to pull the settings and return it in the correct type.
public class SettingDataValue
{
public Guid guid { get; set; }
public string SettingName { get; set; }
public string SettingValue { get; set; }
public string SettingType { get; set; }
}
public static dynamic getSettingFromDB(string name)
{
SettingDataValue s = new SettingDataValue();
using (IDbConnection _db = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString), commandTimeout = null)
{
s = _db.Query<SettingDataValue>("Select Guid, SettingName, SettingValue ,SettingType from SiteSettings where settingName = '" + name + "'").SingleOrDefault();
}
PropertyInfo propertyInfo = s.GetType().GetProperty(s.SettingType);
propertyInfo.SetValue(s, Convert.ChangeType(s.SettingValue, propertyInfo.PropertyType), null);
return s.SettingValue;
}
However when I run this I get a null reference exception on the
propertyInfo.SetValue(s, Convert.ChangeType(s.SettingValue, propertyInfo.PropertyType), null);
I know the query works when I test it and watch it with the sql profiler. Any thoughts or suggestions?
So couple things I had wrong. As David mentioned, I didnt need to use reflection to get the type. Instead I needed to use the Type.GetType method to parse the text. Also the second thing was that the data types have to be the namespace recorded with them.
Here is the updated code that is working now.
public class SettingDataValue
{
public Guid guid { get; set; }
public string SettingName { get; set; }
public string SettingValue { get; set; }
public string SettingType { get; set; }
}
public static dynamic getSettingFromDB(string name)
{
SettingDataValue s = new SettingDataValue();
using (IDbConnection _db = new SqlConnection(ConfigurationManager.ConnectionStrings["NetworkCafeConnectionString"].ConnectionString))
{
s = _db.Query<SettingDataValue>("Select guid, SettingName, SettingValue ,SettingType from SiteSettings where SettingName = '" + name + "'").FirstOrDefault();
}
Type type = Type.GetType(s.SettingType);
var converter = TypeDescriptor.GetConverter(type);
return converter.ConvertFrom(s.SettingValue);
}
Here is a sample of the data in the sql table.
guid SettingName SettingValue SettingType
95473a84 SMCreateTime 00:12:00 System.TimeSpan
81037bdc SMCreateEnabled True System.Boolean
99e06df7 SMUsername Username System.String
The problem you're having isn't that you aren't getting data back, but that the PropertyInfo is null.
The line:
PropertyInfo propertyInfo = s.GetType().GetProperty(s.SettingType);
Is actually trying to find the property "TimeSpan" on the SettingDataValue object (using the line of data you provided). Since this property does not exist it is returning null. Then you're trying to set the value of the property and getting the null reference exception.
I think what you're trying to do is convert the string value to the type of value in the setting type. You don't need to use reflection for that. I'd recommend adding a read only property to your SettingDataValue object:
public object Value
{
get
{
return SomeMethodThatConvertsYourStringValueToTarget();
}
}
Then a private method to actually do the conversion.
private object SomeMethodThatConvertsYourStringValueToTarget();
{
switch (SettingType)
{
case "TimeSpan":
//conversion code
break;
}
}
Then change your getSettingsFromDb method to return object instead of dynamic. Then you can use it like:
TimeSpan ts = (TimeSpan)getSettingsFromDb("SMTimeStart");
Alternatively you may create a method for each data type so you don't have to case it when using it. So you could use it like:
TimeSpan ts = getTimeStampFromDb("SMTimeStart");

C# Multiple Parameter From Single Expression

Do any one know how to send multiple parameter from single expression.
Please refer to my below class;
public class EMP
{
public string NAME { get; set; }
public String FULLNAME { get; set; }
}
I would like to send selective property to a function, something like below.
SendColumn<EMP>(a=>{cl.NAME,cl.FULLNAME})
or
SendColumn<EMP>(cl =>cl.NAME,cl.FULLNAME)
Right now using the below function, I can only send one parameter per expression
public List<TRow> SendColumn<TValue>(Func<TRow, TValue> expression )
{
// do some processing
}
Try using this syntax:
SendColumn(e => new EMP { NAME = "testName", FULLNAME = "TestFullName" });
If that doesn't work, please elaborate on your context and what error you are getting.

Categories

Resources