In this code, I am trying to check what rooms are available at the time that has been entered by the user. To test whether the room is free, I change the roomname to all the options and do a clash check. The problem is, is when I change the room name, it also updates it on my list of existingBookings. Is there a way to make sure that the existingBookings do not change?
var existingBookings = _context.Bookings.ToList();
var booking = await _context.Bookings.SingleOrDefaultAsync(m => m.BookingID == id);
List<Room> roomlist = new List<Room>();
roomlist = (from product in _context.Room
select product).ToList();
List<Room> availableRooms = new List<Room>();
foreach (var item in roomlist)
{
booking.RoomName = item.RoomName;
if (BusinessLogic.BookingChecker.DoesBookingClash(booking, existingBookings) == null)
{
availableRooms.Insert(0, new Room { RoomID = item.RoomID, RoomName = item.RoomName });
}
booking.RoomName = "UNDEF";
}
Thanks for your help!
In order to do so you have to create a new instance of the Booking. You can call the constructor and copy the necessary properties, or implement a ICloneable.Clone method.
public class Booking : ICloneable
{
public Booking Clone()
{
return new Booking() { RoomID = this.RoomID, etc. };
}
object ICloneable.Clone()
{
return this.Clone();
}
}
Then you call it:
booking = booking.Clone();
// use the new booking instance.
The way I fixed this, was to add a new bool field called proposed into the Booking.cs file. When creating the proposed booking, it will automatically set it to true. In my DoesRoomBookingClash I added an if statement to ignore a database entry if proposed was true. Once all the changes are made, proposed is set to false.
Related
I've searched a lot and I think this is possible, but I feel like I am just blocked from knowing how to properly format it.
I have a class representing a product that is a relation class from our CRM to Magento.
Inside the constructor, I have to do some stuff like this...
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
Product existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
this.id = existingMagentoProduct.id;
this.name = existingMagentoProduct.name;
... many of them ...
this.visibility = existingMagentoProduct.visibility;
this.extension_attributes.configurable_product_links = existingMagentoProduct.extension_attributes.configurable_product_links;
}
else
{
// its a new product, new up the objects
this.id = -1;
this.product_links = new List<ProductLink>();
this.options = new List<Option>();
this.custom_attributes = new List<CustomAttribute>();
this.media_gallery_entries = new List<MediaGalleryEntry>();
this.extension_attributes = new ExtensionAttributes();
this.status = 0; // Keep all new products disabled so they can be added to the site and released on a specific day (this is a feature, not an issue / problem).
this.attribute_set_id = netforumProduct.AttributeSetId;
this.visibility = 0;
}
}
It seems silly to have to initialize all of the properties like that. I could use a mapper but that seems like a bandaid. I have to see if the product exists in magento first, and populate its ID and values, otherwise whenever I save the product it creates an additional one.
I considered doing the class constructor calling a static method, but I couldn't get the syntax right.
It might just be too late and I need to think about something else for awhile.
If you must do it in the constructor, you can get rid of a lot of code by first setting 'default' values to the 'Product' properties. This will remove the need to do them in the constructor. Next, if you wanted to automatically set the class's properties, you can use reflection.
public class Product
{
public int Id { get; set; } = -1;
public List<ProductLink> Product_Links { get; set; } = new List<ProductLink>();
....
public int Visibility { get; set; } = 0;
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
var existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
foreach (PropertyInfo property in typeof(Product).GetProperties().Where(p => p.CanWrite))
{
property.SetValue(this, property.GetValue(existingMagentoProduct, null), null);
}
}
}
}
Though, I would like to point out that you probably shouldn't be using a REST client inside a class constructor, especially to just populate its data (also, you are performing a synchronous operation). It would be cleaner to have another layer that is responsible for populating this class using the client, and then use something like AutoMapper to map the data to it.
from what i understand in other posts i know that my objects use same place in memory but how to separate these objects?
i tried to use new but it didn't work or i didn't used it correctly.
Note that i didnt paste setter and getter here.
class Supermarket
{
List<Product> _products = new List<Product>{ };
List<Customer> _customers = new List<Customer>{ };
}
class Customer
{
List<Product> _purchased= new List<Product>{ };
}
class Product
{
string _id;
string _name;
DateTime _expireDate;
int _cost;
int _count;
}
i add one Product in one Method.
Product product = new Product(...);
supermarket.Products.Add(product);
and in another method i want to copy the Product from Supermarket.Products
to Supermarket.Customers.Purchased. so i want a copy but i cant get it.
here i want to make Copy but it does not work.
Product product = supermarket.Products[productIndex];
supermarket.Customers[customerIndex].Purchased.Add(product);
now the problem is when i change Product properties in Customer class , Product properties inside Supermarket will change too.
for example
supermarket.Customers[customerIndex].Purchased.Last().Count = ...
//now the Product supermarket.Products[productIndex] will change too witch is unwanted
The reason why it is not working is because you are doing shallow copy by just adding the pointer of product object into the list, not all properties. So if you change one, another will be affected accordingly.
You can use deep copy following this answer, but this way you have to mark your class as [Serializable]. The simplest way which I think is to use Json serializer:
public static class CloneHelper
{
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
}
var copyProduct = CloneHelper.Clone<Product>(product);
Or simply, you can manage by yourself as the below code, then it works:
Product product = supermarket.Products[productIndex];
Product copyProduct = new Product() {
Id = product.Id,
Name = product.Name,
ExpireDate = product.ExpireDate,
Cost = product.Cost,
Count = product.Count
};
supermarket.Customers[customerIndex].Purchased.Add(copyProduct);
I have a class
public class Orders
{
public Orders() {}
private string _idOrder;
private string _totalPrice;
public string idOrder
{
get{ return _idOrder;}
set { _idOrder = value;}
}
public string totalPrice
{
get { return _totalPrice; }
set { _totalPrice = value; }
}
}
I am loading the list from database like this
while (dr.Read())
{
Orders.idOrder = dr["IdOrder"].ToString();
Orders.totalPrice= dr["totalPrice"].ToString();
}
It's is showing me only last record. How can I load all the orders and retrieve them back by foreach loop?
Create a list :-)
List<Order> orders = new List<Order>();
while (dr.Read())
{
Order order = new Order();
order.idOrder = dr["IdOrder"].ToString();
order.totalPrice= dr["totalPrice"].ToString();
orders.Add(order);
}
As you see, I renamed your class from Orders to Order, because that's what it really represents: One order. To have more orders, you need to put those single orders into a list.
It's only showing you the one item, because you're only changing properties on the one item, not instantiating a new one:
var results = new List<Order>();
while (reader.Read())
{
var order = new Order
{
Id = (int)reader["IdOrder"],
TotalPrice = (decimal)reader["totalPrice"]
};
results.Add(order);
}
I think you are looking for something like this:
IEnumberable<Order> FetchOrders()
{
while(dr.Read())
yield return new Order {
idOrder=dr["IdOrder"].ToString(),
totalPrice=dr["totalPrice"].ToString()
});
}
That Orders class represents a single order! If what you need is a list of orders then I suggest you rename that class to Order, and then create a List<Order> (a list of order-objects) and populate that from your query results.
Also (forgive me for being pernickety) "idOrder" is not a good field name. The standard approaches are "orderId" or just plain old "Id" (ID, or even id). Likewise I would expect the price-of-ONE-order to be called just "amount", or even "price"... not "totalPrice"... it'll be too confusing when you come to total-up the totalPrices... get my drift?
Cheers. Keith.
I don't see how that will compile. Orders.idOrder is not a static property, it's an instance property.
If i understand you right you want to use something like this:
List<Order> = new List<Order>();
while (dr.Read())
{
Order newOrder = new Order();
newOrder.idOrder = dr["IdOrder"].ToString();
newOrder.totalPrice= dr["totalPrice"].ToString();
orderList.Add(newOrder);
}
Notice this that I just discuss more for #Grook Answer. I Think it is so near to what to want.
IEnumberable<Order> FetchOrders()
{
while(dr.Read())
yield return new Order {
idOrder=dr["IdOrder"].ToString(),
totalPrice=dr["totalPrice"].ToString()
});
}
Then You can easily use foreach loop
Foreach(Order order in GetOrders())
{
doSomething(order);
}
Is it clear?
I have a linq query where I am creating several classes which have a Parent property on them. I am looking for a way to set the parent property to be the class I just created. My explanation sucks; here's code of what I'm trying to do.
var query = from states in xml.Elements()
select new State
{
Children = from cities in states.Elements()
select new City()
{
ParentState = **???**;
}
};
How do I set the ParentState property? If I could do something like
select new State as newState
{
...
}
that would be cool, but I can't. I know I can do this with a foreach loop, but I would like to learn how, if possible, to do this with LINQ. Help :(
EDIT: I tried
let x = new State{ } but that didn't help much. I was hoping I could refer to x in the constructor like this but it didn't work out:
let x = new State
{
Children = from cities in states.Elements()
select new City{ ParentState = x }
}
select x;
In F#, there is something similar to this where you can simply say let rec x = ...
and then you can refer to the variable inside of the assignment statement. But this is C# not F# so whatever.
Interesting problem, and there may certainly be a way to do it by setting the properties right in the query statement, but I think another possibility is to move some of that logic to a constructor within State. Consider the following code example
class State
{
public int Id { get; set; }
public List<City> Children { get; set; }
public State(int id, IEnumerable<City> childrenCities)
{
this.Id = id;
this.Children = childrenCities.ToList();
foreach (City city in this.Children)
city.ParentState = this;
}
}
This State class has a constructor which accepts an enumerable of City objects. It then loops over the objects and sets the ParentState property.
And then instead of setting the properties with the query expression, you instead invoke the constructor.
// not LINQ-to-XML, just an example
var states = from i in Enumerable.Range(0, 10)
select new State(
i,
from j in Enumerable.Range(0, 5)
select new City
{
Id = j
}
);
Hey, I think this is what you need
var query = from states in xml.Elements()
select new State
{
Children = from cities in states.Elements()
select new City()
{
ParentState = new State{
Property1 = states.XElement("Property1").Value
}
}
};
the variable states is the current state. I presume the "states" var is an XElement and holds the data to populate the parentstate property
Hope this helps
I have a constructor something like the following:
using Microsoft.Data.Extensions;
public class Complaint
{
public int Id {get; set;}
public int Transcript {get; set;}
//... etc. ... Lots more properties
public Complaint(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
this.Id = complaint.Id;
this.Transcript = complaint.Transcript;
//... etc. ... Lots more properties to set
}
}
Is there a syntax in C# that would allow me to carry out the last part in one step instead of two? i.e. conceptually something like this:
this = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
}
Well, you could use a static method instead of a constructor:
public static Complaint FromId(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
return command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
});
}
Not inherently. You could store the complaint object inside the class, and have all the properties point off that rather than setting them all from the constructor.
eg
public class Complaint
{
private readonly {type of complaint} m_Complaint;
public int Id
{
get { return m_Complaint.Id; }
}
// ...etc
}
You could get more complicated if you don't have a setter on m_Complaint - keeping nullable backing fields, and check that before you access the m_Complaint properties
I believe you may try something like this:
var currentInstance = this;
var complaint = command.Materialize(x =>
new Complaint
{
Id = currentInstance.Id = x.Field("Id"),
Transcript = currentInstance.Transcript = x.Field("Transcript");
//... etc. ... Lots more fields from db
});
I don't think you can capture this in the closure, so using that currentInstance trick should help, however it may as well turn out to be redundant.
Besides, code such as that one is sort of obfuscated compared to your current solution. I believe that your code is pretty fine as it is.
I gather that you're trying to avoid setting all of those properties twice, because any change to the structure requires you to update the properties in two places, is that correct?. You could try to use some reflection to copy the properties from one instance to another.
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
foreach (var prop in typeof(Complaint).GetProperties())
...
Have the complaint object as a member variable and the get/set properties accesses the underlying complaint's properties?