Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
When Domain Model property Name gets data from the database it's a string "David,James", but I have created another View Model to convert that string into an array ["David","James"]. I have used my ViewModel in the read method now, now the ViewModel should read the Name property as ["David","James"]. I am not sure how to make it happen.
I would appreciate if anybody has any suggestion on how to make it happen.
Domain Model:
public class FullName
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Address {get; set;}
}
View Model:
public class NameViewModel
{
public Int32 Id { get; set; }
public List<string> Name { get; set; }
public String Address { get; set;}
}
Read Method:
public ActionResult Name_Read([DataSourceRequest]DataSourceRequest request)
{
try
{
DataSourceResult result = Identity.ToDataSourceResult(request, NameViewModel => new
{
Id = NameViewModel.Id,
Name = NameViewModel.Name ,
Address = NameViewModel.Address,
});
return Json(result);
}
I think you're looking for something like this:
DataSourceResult result = Identity.ToDataSourceResult(request, dataModel => new NameViewModel
{
Id = dataModel.Id,
Name = dataModel.Name.Split(","),
Address = dataModel.Address,
});
// typical delimiter characters
char[] delimiterChars = { ' ' };
// verify the name exists
if (!String.IsNullOrEmpty(name))
{
// Get the list of strings
string[] strings = name.Split(delimiterChars);
if (strings != null)
{
if (strings.Length == 1)
{
firstName = strings[0];
}
else if (strings.Length == 2)
{
firstName = strings[0];
lastName = strings[1];
}
else if (strings.Length == 3)
{
firstName = strings[0];
middleName = strings[1];
lastName = strings[2];
}
}
}
I am not at Visual Studio, but I think that is right.
When Domain Model property Name gets data from the database it's a string "David,James"
That is a terrible mistake in database Design. The ideal solution would be to fix the Backend Database to actually have two fields for those distinct values.
Failing that, the next step would be to try and split on the DB side. Many modern DBMS support Views, wich can have columns computed from actuall rows. That way you could avoid issues, like different code splitting the same input differently. And you could even henceforth treat it like it was always two Columns.
If you really want or need to it in code and given this exact input format, String.Split() can deal with this. Of coruse you can get fancier, and use stuff like Regular Expressions instead. But for this example, Split seems perfectly suiteable for the case.
Related
I'm fetching data from website that returns me an object in a string like this:
{
index: 1,
commentNumber: 20,
feedComments: {
3465665: {
text: "I do not agree",
likeRatio: 0
},
6169801: {
text: "Hello",
likeRatio: 12
},
7206201: {
text: "Great job!",
likeRatio: 5
}
}
}
I want to work with this as an object, that's pretty easy to do, I'll just do this:
string objectString = GetData(); // Artificial GetData() method
dynamic data = JObject.Parse(objectString);
And now I can easily get all properties I want from this object using dynamic
The problem is pretty obvious now, I want to get properties, whose name starts with number (the object data structure I fetch is just designed that way). But property/field names you get from object cannot begin with a number.
int commentNumber = data.commentNumber; // Works fine
string commentText = data.feedComments.3465665.text; // Obviously won't compile
Is there any way to do this?
Note that I want to work with data I fetch as it was an object, I know I get get the comment text right from the string that GetData() method returns using some regex or something, but that's something I want to avoid.
You should really be parsing the JSON into concrete C# classes. Dynamic is slow and vulnerable to runtime errors that are hard to detect.
The comments will go into a Dictionary. For example:
public class Root
{
public int Index { get; set; }
public int CommentNumber { get; set; }
public Dictionary<long, FeedComment> FeedComments { get; set; }
}
public class FeedComment
{
public string Text { get; set; }
public int LikeRatio { get; set; }
}
And deserialise like this:
var result = JsonConvert.DeserializeObject<Root>(objectString);
Now you can access the comments very easily:
var commentText = result.FeedComments[3465665].Text
I have re edit this question below I have an example file which as multiple purchase orders in the file which is identified by the second column.
Order Number, Purchase Number,DATE,Item Code ,Qty, Description
1245456,98978,12/01/2019, 1545-878, 1,"Test"
1245456,98978,12/01/2019,1545-342,2,"Test"
1245456,98978,12/01/2019,1545-878,2,"Test"
1245456,98979,12/02/2019,1545-878,3,"Test 3"
1245456,98979,12/02/2019,1545-342,4,"Test 4"
1245456,98979,12/02/2019,1545-878,5,"Test 4"
What I want the end result to be is to be able to place the above into one class like the following
At the min I am using filelpers to parse the csv file this would work fine if I had sep header file and row file but they are combined as you see
var engine = new FileHelperEngine<CSVLines>();
var lines = engine.ReadFile(csvFileName);
So the Class should be like below
[DelimitedRecord(",")]
public class SalesOrderHeader
{
private Guid? _guid;
public Guid RowID
{
get
{
return _guid ?? (_guid = Guid.NewGuid()).GetValueOrDefault();
}
}
public string DocReference { get; set; }
public string CardCode { get; set; }
public string DocDate { get; set; }
public string ItemCode { get; set; }
public string Description { get; set; }
public string Qty { get; set; }
public string Price { get; set; }
[FieldHidden]
public List<SalesOrderHeader> OrdersLines { get; set; }
}
What I imagine I will have to do is two loops as you will see from my createsales order routine i first create the header and then add the lines in.
public void CreateSalesOrder(List<SalesOrderHeader> _salesOrders)
{
foreach (var record in _salesOrders.GroupBy(g => g.DocReference))
{
// Init the Order object
oOrder = (SAPbobsCOM.Documents)company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oOrders);
SAPbobsCOM.SBObob oBob;
// set properties of the Order object
// oOrder.NumAtCard = record.Where(w=>w.RowID = record.Where()
oOrder.CardCode = record.First().CardCode;
oOrder.DocDueDate = DateTime.Now;
oOrder.DocDate =Convert.ToDateTime(record.First().DocDate);
foreach (var recordItems in _salesOrders.SelectMany(e=>e.OrdersLines).Where(w=>w.DocReference ==record.First().DocReference))
{
oOrder.Lines.ItemCode = recordItems.ItemCode;
oOrder.Lines.ItemDescription = recordItems.Description;
oOrder.Lines.Quantity = Convert.ToDouble(recordItems.Qty);
oOrder.Lines.Price = Convert.ToDouble(recordItems.Price);
oOrder.Lines.Add();
log.Debug(string.Format("Order Line added to sap Item Code={0}, Description={1},Qty={2}", recordItems.ItemCode, recordItems.Description, recordItems.Qty));
}
int lRetCode = oOrder.Add(); // Try to add the orer to the database
}
if(lRetCode == 0)
{
string body = "Purchase Order Imported into SAP";
}
if (lRetCode != 0)
{
int temp_int = lErrCode;
string temp_string = sErrMsg;
company.GetLastError(out temp_int, out temp_string);
if (lErrCode != -4006) // Incase adding an order failed
{
log.Error(string.Format("Error adding an order into sap ErrorCode {0},{1}", temp_int, temp_string));
}
}
}
The problem you will see i have is how do I first split the csv into the two lists and second how do i access the header rows correctly in the strongly type object as you see I am using first which will not work correctly.
With FileHelpers it is important to avoid using the mapping class for anything other than describing the underlying file structure. Here I suspect you are trying to map directly to a class which is too complex.
A FileHelpers class is just a way of defining the specification of a flat file using C# syntax.
As such, the FileHelpers classes are an unusual type of C# class and you should not try to use accepted OOP principles. FileHelpers should not have properties or methods beyond the ones used by the FileHelpers library.
Think of the FileHelpers class as the 'specification' of your CSV format only. That should be its only role. (This is good practice from a maintenance perspective anyway - if the underlying CSV structure were to change, it is easier to adapt your code).
Then if you need the records in a more 'normal' object, then map the results to something better, that is, a class that encapsulates all the functionality of the Order object rather than the CSVOrder.
So, one way of handling this type of file is to parse the file twice. In the first pass you extract the header records. Something like this:
var engine1 = new FileHelperEngine<CSVHeaders>();
var headers = engine1.ReadFile(csvFileName);
In the second pass you extract the details;
var engine2 = new FileHelperEngine<CSVDetails>();
var details = engine2.ReadFile(csvFileName);
Then you combine this information into a new dedicated class, maybe with some LINQ similar to this
var niceOrders =
headers
.DistinctBy(h => h.OrderNumber)
.SelectMany(d => details.Where(d => d.OrderNumber = y))
.Select(x =>
new NiceOrder() {
OrderNumber = x.OrderNumber,
Customer = x.Customer,
ItemCode = x.ItemCode
// etc.
});
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I'm using a web service with this request format:
{
"type":"LogonReq",
"id":"b43b301c-5216-4254-b3fc-cc863d4d6652",
"date":"Wed, 16 Aug 2017 17:35:34 UTC",
"parameters":[
{
"userName":"user",
"password":"password"
}
]
}
Even though every message in the API requires only 1 set of parameters, the API still requires "parameters" to be an array.
Is it better practice to have the caller create the list or to create the list in the MessageBase constructor, or something altogether different ?
Which way would satisfy an OOP purist code reviewer?
public class MessageBase<T>
{
public MessageBase() { this.parameters = new List<T>(); }
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
};
logon.parameters.Add(new LogonMessage() { userName = "user", password = "password" });
or
public class MessageBase<T>
{
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
parameters = new List<LogonMessage>() { new LogonMessage() { userName = "user", password = "password" } }
};
You will probably find many interesting opinions and answers to this. I can only give you mine based on my experience.
I myself would probably initialize the list within the constructor
However, since you are trying to get a good idea around the phylosophy of coding, here are some things to consider :
1) Does the MessageBase object make sense or is it useful with a NULL list? Is there any scenario where I want this list as null?
2) Actually, I would expect an OOP purist to say that you should not expose the "parameters" as a List. By exposing the object as a property, someone can do this:
login.parameters.Add()
Or this
logon.parameters = anotherListOfMine
In a way it does break encapsulation. You could make the list property read only (ie, with a protected/private setter) but "clients" of this class will still be able to access all properties and methods of the List and modify/handle them.
Now, you have to expose this in some way as you will be serializing/deserializing into JSON, so that poses a problem! Maybe you can have a private/protected List field and expose the values through a readonly property that exposes an IEnumerable and behind the scenes, you are doing:
get { return myPrivateList.ToArray(); }
3) But again, do you really win that much? Your next question should be "Who is my client?" If you are exposing this class to other developers, or is part of a framework, you might want to apply something like my point number 2, and limit the exposure. If this is internal to your application and your team maybe you should be pragmatic and simply expose the List as you are doing right now.
4) Alternatively, while still making it open, you could instead have a property of type IEnumerable so you can pass in any type.
5) Another option is to expose your list because you need to serialize it, but make it readonly. Have instead different methods, or non-serializable properties, of username and password. If these parameters are always the same that is. I am thinking this might not be your case.
I think I could go on and on this. I will stop here before you hit the downvote button :).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
combobox.Items.Add(object item), so why we can use combobox.Items.Add("Some text"), although "Some text" is string, not object?
A string is a reference type, so it is an object. What combobox does is then call the .ToString() method of the object it receives to transform it in a string (to show it). The ToString() of a string simply returns the string.
Why is the Add() done in that way?
Let's look at an example using WinForms:
// A simple Person class, Name + Surname
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public override string ToString()
{
return Name + " " + Surname;
}
}
// cb is your ComboBox
// Three persons in the ComboBox
cb.Items.Add(new Person { Name = "Bill", Surname = "Gates" });
cb.Items.Add(new Person { Name = "Larry", Surname = "Ellison" });
cb.Items.Add(new Person { Name = "Peter", Surname = "Norton" });
// and then somewhere the user selects an item in the combobox
// and then we can
Person selectedPerson = (Person)cb.SelectedItem;
string selectedPersonDescription = cb.SelectedText;
You can retrieve not only the description of the selected item, but the "whole" selected item! You see the advantage? (as I said before, the "description" for the items is automatically calculated by the ComboBox class by using the ToString() method)
So clearly the ComboBox is saving the "whole" objects you Add(...) to it, and calculating the descriptions (with ToString()) to show to the user.
It's thanks to polymorphism. Because string derives from object, you can pass it to the method, as well as any other instance of type deriving from object (which is almost everything).
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am new to both SPA and Entity Framework and I have a question about the right/preferred way to do this.
I've got a web page to search customers by some filters (like name, surname, birthday date, phone number).
With ajax I pass from View to Controller a ViewModel object like this:
public class CustomerSearch
{
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? Birthday{ get; set; }
public string Phone{ get; set; }
}
Into controller I've got this search method:
public List<CustomerList> GetCustomersList(CustomerSearch cs)
{ ..... }
In my application there are also DataAccess objects.
Now, the question is: how I can to do the query to database in smart mode?
I've thinked some scenario but i don't know which is the best about the layer separation.
I can ask to model an IQueryable object and perform the Where condition into controller
I can create a DataAccess method with the filters like parameters
I can create a Customer object (model object) filled with the filters value and pass this to model that perform the query
Which is the best method?
Thanks in advance.
Daniele
I would suggest the first option you present for the following reasons:
Your second option would possibly require a lot of parameters if the number of possible search queries grows. It is generally not recommended to have a very large number of parameters since it leads to readability issues. (e.g. calling a method with 30 parameters)
Your third option would make it impossible to create a query like 'BirthDate in 1998' or 'Surname starts with Q'.
By creating a class specifically for the purposes of querying you can do something like the following:
public class CustomerQuery
{
public string Name { get; set; }
public DateTime? BirthDay { get; set; }
internal IQueryable<Customer> Apply(IQueryable<Customer> query)
{
var result = query;
if (!string.IsNullOrWhiteSpace(Name))
{
result = result.Where(c => c.Name == Name);
}
if (BirthDay.HasValue)
{
result = result.Where(c => c.BirthDay == BirthDay.Value);
}
return result;
}
}
Pay specific attention to the internal visibility of the Apply method. If you define this class in your Data Access Layer and this is defined in a separate C# project, the Apply method will only be visible to this Data Access Layer and not to the GUI project.
Calling it would be:
public List<Customer> GetCustomersList(CustomerQuery customerQuery)
{
using (var context = new MyDbContext())
{
var customers = context.Customers;
return customerQuery.Apply(customers).ToList();
}
}
This can be further extended to support e.g. different types of string search (Contains, StartsWith etc):
public enum TextFilterType
{
StartsWith,
EndsWith,
Contains,
ExactMatch
}
public class StringQuery
{
private readonly string _value;
private readonly TextFilterType _filterType;
public StringQuery(string value, TextFilterType filterType)
{
_value = value;
_filterType = filterType;
}
public string Value
{
get { return _value; }
}
public TextFilterType FilterType
{
get { return _filterType; }
}
}
If we would apply this to the CustomerQuery type:
public class CustomerQuery
{
public StringQuery Name { get; set; }
}
Then you look at the FilterType property of the StringQuery to find out if you need to do Contains, StartsWith etc.