I need to find the lowest customer id in the array and increase it by 1.
So I need the for cycle to search for the biggest id (0 by default) and increase by 1 every time ( create a new object of the customer class.
I really don't know how to implement the "i" value in order to make the cycle search for the id...
My model:
public class CustomerModel
{
public int IDCustomer {get; set;}
public string LastNameCustomer {get; set;}
public string FirstNameCustomer {get; set;}
public string AdressCustomer {get; set;}
}
My algorithm attempt:
CustomerModel[] MemoryCustomers = new CustomerModel[9];
OrderModel[] MemoryOrders = new OrderModel[9];
public string CreateCustomer(CustomerModel model)
{
CustomerModel NewCustomer = new CustomerModel();
for (int i = 0; i < 10; i++)
{
//What to put here
}
}
it is not a good practice to do that, you can use "SQL identity" if dealing with database.
or you can use type GUID to generate unique identifier for each customer.
Don't do that.
You should instead try to get the next id for a customer from some external provider. If you're using a database system, that can generate indices for you - you just need to define a counter or ID-generator or some such thing in the DBMS. How that is done depends on which DB you are using.
Otherwise, you could create your own method that you can call each time you need a new id; something like:
newCustomer.IDCustomer = GetNextId();
If doing that, make sure the method can never return any ID more than once, and you should be safe. There are several ways to do this; one is to constantly increase a number. Another is to use an UUID or GUID:
var id = Guid.NewGuid().ToString() // Generate a universally unique ID-string
The latter is especially useful if you want ID's that appear random, so that knowing one or two ID's won't make it easy to guess others (a common security problem / weakness in many apps).
Update:
Ok, ok: If you really want to simply get the next available ID as an int, based on existing int's, then try this:
private int GetNextId(){
// Create a list for easy handling with LINQ:
List<CustomerModel> customers = new List<CustomerModel)(MemoryCustomers);
// Select only ids, and only the highest:
int highestExistingId = customers
.Select(cust => cust.IDCustomer)
.Max();
return highestExistingId + 1;
}
If I've understood your question correctly now after re-reading it, I believe you want to update the lowest ID in your array, and replace it with a new customer,with the new ID - is that correct?
If so, try:
List<CustomerModel> customers = new List<CustomerModel)(MemoryCustomers);
var lowestId = customers.Select(cust => cust.IDCustomer).Min();
for (int i = 0; i < 10; i++)
{
// Identify the customer with that lowest id...
if(MemoryCustomers[i].IDCustomer == lowestId)
{
// ... replace him with the new one:
MemoryCustomers[i] = NewCustomer;
}
}
This may not be what you are searching for but it should work more consistent.
Add something like this to your Customer-Class:
private static int last_gen_id = -1;
public static int Gen_ID {
get {
last_gen_id++;
return last_gen_id;
}
}
And for every id, you want to generate, you just call Customer.Gen_ID and you got yourself a unique id. This will not work with threading, so be warned ;)
Related
I want to iterate through my table, check to see if the Quantity received is higher than the quantity expected for each row, and if so execute some code.
The way I've done it below feels amateurish.
bool allRecieved = true;
foreach (DataRow row in SubVwr.Tables[0].Tbl.Rows)
{
if(row["QtyRcvd"] < row["QtyPer"]) allRecieved = false;
}
if(allRecieved) // execute code
You can use LINQ, for better readability (presuming those are int-columns):
bool allRecieved = SubVwr.Tables[0].Tbl.AsEnumerable()
.All(row => row.Field<int>("QtyRcvd") >= row.Field<int>("QtyPer"));
An advantage over your current loop is that this will stop as soon as one record doesn't match this condition. Your loop will continue until end without break.
This is a bit radical, but I'd start by not using DataTable, and instead use a simple model:
public class SomeType {
// I'd probably name these QuantityReceived etc, but... meh
public int QtyRcvd {get;set;}
public int QtyPer {get;set;}
// ... etc
}
Then I can very conveniently check properties etc. For example, to mirror Tim Schmelter's LINQ answer:
List<SomeType> someData = ...
var allReceived = someData.All(x => x.QtyRcvd >= x.QtyPer);
so now all we need is to load SomeType from the DB, which is where ORMs and micro-ORMs excel. For example, with "Dapper", this would be:
string region = "North"; // just to show parameter usage
var someData = connection.Query<SomeType>(
#"select * from SomeTable where Region=#region", new { region }).AsList();
I am getting data via a SqlDataReader and now looping through the results and putting the results in the list. I am trying to add 2 columns to each list, but I am unsuccessful.
Here is my code:
for (int i = 0; i < reader.FieldCount; i++)
{
List<string> costs = new List<string>();
if (reader.GetName(i).ToString().Contains("TotalCost"))
{
costs.Add(reader.GetValue(i).ToString());
}
if (reader.GetName(i).ToString().Contains("SqftCost"))
{
costs.Add(reader.GetValue(i).ToString());
}
jobList.Add(costs);
}
But this puts the two columns in separate lists, I really need the 2 columns in one list.
The reason I am doing it like this is because I have columns that are called TotalCost101, SqftCost101, TotalCost102, SqftCost102, TotalCost104, SqftCost104. So each column that contains TotalCost and SqftCost should be in its own list. I hope this makes sense, anyone got any ideas on how to put these 2 columns in their own list. So at the end I will have a bunch of lists with 2 values.
I updated my code so I now use a Class instead of a List
for (int i = 0; i < reader.FieldCount; i++)
{
CostMatrix costs = new CostMatrix();
if (reader.GetName(i).ToString().Contains("TotalCost"))
{
costs.TotalCost = reader.GetValue(i).ToString();
}
if (reader.GetName(i).ToString().Contains("SqftCost"))
{
costs.sqftCost = reader.GetValue(i).ToString();
}
jobList.Add(costs);
}
Here is the current output:
<d3p1:CostMatrix>
<d3p1:TotalCost>550</d3p1:TotalCost>
<d3p1:sqftCost i:nil="true"/>
</d3p1:CostMatrix>
<d3p1:CostMatrix>
<d3p1:TotalCost i:nil="true"/>
<d3p1:sqftCost>0.41</d3p1:sqftCost>
</d3p1:CostMatrix>
What I am looking for is:
<d3p1:CostMatrix>
<d3p1:TotalCost>550</d3p1:TotalCost>
<d3p1:sqftCost>0.41</d3p1:sqftCost>
</d3p1:CostMatrix>
Honestly, I would use an object.
public class Price
{
public decimal Sqft { get; set; }
public decimal Total { get; set; }
}
You have an object that actually represents something tangible. You're clearly indicating what type of price is applicable. This will avoid confusion with other people working on the project and for you, with an expressive usage. Nothing is being obfuscated into a Tuple or string.
Then when you use the data reader, you could do something along these lines:
public static T GetValueOrNull<T>(this IDataReader reader, string column)
{
int ordinal;
if(!string.IsNullOrEmpty(column) && !reader.IsDBNull(reader.GetOrdinal(column)))
if(int.TryParse(reader.GetOrdinal(column).ToString(), out ordinal))
return (T)reader.GetValue(ordinal);
return default(T);
}
You can basically tell this, "which column" then assign it to that property. This could also be handled by some form of object relational mapper.
// Example:
List<Product> products = db.GetProducts();
var example = products.Where(o => o.Price.Sqft >= 5.00);
var sample = products.Where(o => o.Price.Total <= 5.00);
You can store Price inside of another object, allowing a web-site to filter a product based on how multiple types of price values, for instance. It has other benefits as well, it will also document your code nicely, to know how pricing may be implemented.
Not search for a collection of strings, how would that persist throughout your application? A List<string> would be hard to find all implementations for price, unless seeking a data attribute. But these are a bunch of reasons.
Hope this clarifies a bit.
Based on your update, you could do:
public class CostMatrix
{
public ConcurrentList<decimal> Total { get; set; }
public ConcurrentList<decimal> Sqft {get; set; }
}
Your object would have two separate list, then as you read through the table column by column and row by row, you could simply add. So if you used the above static method it would be:
using(var connection = new SqlConnection(dbConnection))
using(var command = new SqlCommand(query, dbConnection))
using(var reader = new SqlDataReader())
while(reader.Read())
{
Total.Add(GetValueOrNull<decimal>(reader, "TotalCost");
Sqft.Add(GetValueOrNull<decimal>(reader, "Sqft1");
}
I placed ConcurrentList because your implementation may use async. Wasn't sure, if not you can use a normal List. But a List isn't thread safe by default, you'd need a ConcurrentList.
I currently have a list of objects that I am trying sort for a custom made grid view. I am hoping that I can achieve it without creating several customized algorithms. Currently I have a method called on page load that sorts the list by customer name, then status. I have a customized status order (new, in progress, has issues, completed, archived) and no matter which sort is used (customer, dates, so on) it should sort the status in the correct order. For example:
I have two customers with two orders each, the first customer is Betty White, the second is Mickey Mouse. Currently, Betty has a new order, and a completed order and Mickey has an order in progress and another on that has issues. So the display order should be:
Betty, New :: Betty, Completed
Mickey, In Progress :: Mickey, Has Issues
I am currently using Packages.OrderBy(o => o.Customer).ThenBy(o => o.Status). This works effectively to get the customers sorted, however this doesn't eliminate the custom sorting of the status property.
What would be the most efficient and standards acceptable method to achieve this result?
case PackageSortType.Customer:
Packages = Packages.OrderBy(o => o.Customer).ThenBy(o=>o.Status).ToList<Package>();
break;
I previously created a method that sorted by status only, however it is my belief that throwing the OrderBy into that algorithm would just jumble the status back up in the end.
private void SortByStatus() {
// Default sort order is: New, In Progress, Has Issues, Completed, Archived
List<Package> tempPackages = new List<Package>();
string[] statusNames = new string[5] { "new", "inProgress", "hasIssue", "completed", "archived" };
string currentStatus = string.Empty;
for (int x = 0; x < 5; x++) {
currentStatus = statusNames[x];
for (int y = 0; y < Packages.Count; y++) {
if (tempPackages.Contains(Packages[y])) continue;
else {
if (Packages[y].Status == currentStatus)
tempPackages.Add(Packages[y]);
}
}
}
Packages.Clear();
Packages = tempPackages;
}
Also, I'm not sure if it is relevant or not; however, the Packages list is stored in Session.
EDIT
Thanks to Alex Paven I have resolved the issue of custom sorting my status. I ended up creating a new class for the status and making it derive from IComparable, then created a CompareTo method that forced the proper sorting of the status.
For those who are curious about the solution I came up with (it still needs to be cleaned up), it's located below:
public class PackageStatus : IComparable<PackageStatus> {
public string Value { get; set; }
int id = 0;
static string[] statusNames = new string[5] { "new", "inProgress", "hasIssue", "completed", "archived" };
public int CompareTo(PackageStatus b) {
if (b != null) {
if (this == b) {
return 0;
}
for (int i = 0; i < 5; i++) {
if (this.Value == statusNames[i]) { id = i; }
if (b.Value == statusNames[i]) { b.id = i; }
}
}
return Comparer<int>.Default.Compare(id, b.id);
}
}
Use:
Packages.OrderBy(o => o.Customer).ThenBy(o => o.Status).ToList<Package>();
I'm not sure what exactly you're asking; why can't you use the Linq expressions in your first code sample? There's OrderByDescending in addition to OrderBy, so you can mix and match the sort order as you desire.
I have a C# program where I have a list (List<string>) of unique strings. These strings represent the name of different cases. It is not important what is is. But they have to be unique.
cases = new List<string> { "case1", "case3", "case4" }
Sometimes I read some cases saved in a text format into my program. Sometime the a case stored on file have the same name as a case in my program.I have to rename this new case. Lets say that the name of the case I load from a file is case1.
But the trouble is. How to rename this without adding a large random string. In my case it should ideally be called case2, I do not find any good algorithm which can do that. I want to find the smalles number I can add which make it unique.
i would use a HashSet that only accepts unique values.
List<string> cases = new List<string>() { "case1", "case3", "case4" };
HashSet<string> hcases = new HashSet<string>(cases);
string Result = Enumerable.Range(1, 100).Select(x => "case" + x).First(x => hcases.Add(x));
// Result is "case2"
in this sample i try to add elements between 1 and 100 to the hashset and determine the first sucessfully Add()
If you have a list of unique strings consider to use a HashSet<string> instead. Since you want incrementing numbers that sounds as if you actually should use a custom class instead of a string. One that contains a name and a number property. Then you can increment the number and if you want the full name (or override ToString) use Name + Number.
Lets say that class is Case you could fill a HashSet<Case>. HashSet.Add returns false on duplicates. Then use a loop which increments the number until it could be added.
Something like this:
var cases = new HashSet<Case>();
// fill it ...
// later you want to add one from file:
while(!cases.Add(caseFromFile))
{
// you will get here if the set already contained one with this name+number
caseFromFile.Number++;
}
A possible implementation:
public class Case
{
public string Name { get; set; }
public int Number { get; set; }
// other properties
public override string ToString()
{
return Name + Number;
}
public override bool Equals(object obj)
{
Case other = obj as Case;
if (other == null) return false;
return other.ToString() == this.ToString();
}
public override int GetHashCode()
{
return (ToString() ?? "").GetHashCode();
}
// other methods
}
The solution is quite simple. Get the max number of case currently stored in the list, increment by one and add the new value:
var max = myList.Max(x => Convert.ToInt32(x.Substring("case".Length))) + 1;
myList.Add("case" + max);
Working fiddle.
EDIT: For filling any "holes" within your collection you may use this:
var tmp = myList;
var firstIndex = Convert.ToInt32(myList[0].Substring("case".Length));
for(int i = firstIndex; i < tmp.Count; i++) {
var curIndex = Convert.ToInt32(myList[i].Substring("case".Length));
if (curIndex != i)
{
myList.Add("case" + (curIndex + 1));
break;
}
}
It checks for every element in your list if its number behind the case is equal to its index in the list. The loop is stopped at the very first element where the condition is broken and therefor you have a hole in the list.
I have a DB like this that I generated from EF:
Now I'd like to add a "fielduserinput" entity so I write the following code:
public bool AddValueToField(string field, string value, string userId)
{
//adds a value to the db
var context = new DBonlyFieldsContainer();
var fieldSet = (from fields in context.fieldSet
where fields.fieldName.Equals(field)
select fields).SingleOrDefault();
var userSet = (from users in context.users
where users.id.Equals(userId)
select users).SingleOrDefault();
var inputField = new fielduserinput { userInput = value, field = fieldSet, user = userSet };
return false;
}
Obviously it's not finished but I think it conveys what I'm doing.
Is this really the right way of doing this? My goal is to add a row to fielduserinput that contains the value and references to user and field. It seems a bit tedious to do it this way. I'm imagining something like:
public bool AddValueToField(string userId, string value, string fieldId)
{
var context = new db();
var newField = { field.fieldId = idField, userInput = value, user.id = userId }
//Add and save changes
}
For older versions of EF, I think you're doing more or less what needs to be done. It's one of the many reasons I didn't feel EF was ready until recently. I'm going to lay out the scenario we have to give you another option.
We use the code first approach in EF 4 CTP. If this change is important enough, read on, wait for other answers (because Flying Speghetti Monster knows I could be wrong) and then decide if you want to upgrade. Keep in mind it's a CTP not an RC, so considerable changes could be coming. But if you're starting to write a new application, I highly recommend reading some about it before getting too far.
With the code first approach, it is possible to create models that contain properties for a reference to another model and a property for the id of the other model (User & UserId). When configured correctly setting a value for either the reference or the id will set the id correctly in the database.
Take the following class ...
public class FieldUserInput{
public int UserId {get;set;}
public int FieldId {get;set;}
public virtual User User {get;set;}
public virtual Field Field {get;set;}
}
... and configuration
public class FieldUserInputConfiguration{
public FieldUserInputConfiguration(){
MapSingleType(fli => new {
userid = fli.UserId,
fieldid = fli.FieldId
};
HasRequired(fli => fli.User).HasConstraint((fli, u)=>fli.UserId == u.Id);
HasRequired(fli => fli.Field).HasConstraint((fli, f)=>fli.FieldId == f.Id);
}
}
You can write the code...
public void CreateField(User user, int fieldId){
var context = new MyContext();
var fieldUserInput = new FieldUserInput{ User = user, FieldId = fieldId };
context.FieldUserInputs.Add(fieldUserInput);
context.SaveChanges();
}
... or vice versa with the properties and everything will work out fine in the database. Here's a great post on full configuration of EF.
Another point to remember is that this level of configuration is not necessary. Code first is possible to use without any configuration at all if you stick to the standards specified in the first set of posts referenced. It doesn't create the prettiest names in the database, but it works.
Not a great answer, but figured I'd share.