I wrote a program that does work with files like delete and update, store, and search
And all customers
But I have a problem with the method is LoadAll
Once the data are read from the file and then Deserialize the object becomes
But when I want to save the list of objects in the list are repeated.
How can I prevent the duplication in this code?
var customerStr = File.ReadAllLines (address);
The code is written in CustomerDataAccess class DataAccess Layer.
Project File
The main problem with the method LoadAll Code:
public ICollection<Customer> LoadAll()
{
var alldata = File.ReadAllLines(address);
List<Customer> lst = new List<Customer>();
foreach (var s in alldata)
{
var objCustomer = customerSerializer.Deserialize(s);
lst.Add(objCustomer);
}
return lst;
}
CustomerSerialize class defined in a Field you simply use the Deserialize method you! Each series is a series Deserialize the value added items previously got into the game! (Because there is reference Type).
If you change your code to:
public Customer Deserialize(string str)
{
**Customer customer = new Customer();**
var strCustomer = str.Split(',');
customer.Id = int.Parse(strCustomer[0]);
customer.FirstName = strCustomer[1];
customer.LastName = strCustomer[2];
customer.Age = int.Parse(strCustomer[3]);
customer.Country = strCustomer[4];
return customer;
}
Related
I am new to programming and been tasked to grab data from an API.
The issue I have is basic C# returning the contents of brakeparts. I'm passing the part id and obtaining a list of brake parts correctly. I need to assign the partid to the list, which seems to work when adding a breakpoint, however how do I return this list? Return brake parts doesn't work. They could be potentially many parts it returns whilst looping I need it to append to the Parts list. I know its probably something quite simple but I can't get my head around returning back the whole list. I've tried brakeparts.AddRange(brakeparts); This doesn't work too.
private static List<Parts> getBrakeparts(List<int> partids)
{
var restClient = new RestClient("https://example.example.net/api");
foreach (var partid in partids)
{
var returnreq = new RestRequest($"/brakeparts/{partid}/ ", Method.GET);
var res = restClient.Execute(returnreq);
Parts brakeparts = JsonConvert.DeserializeObject<Parts>(res.Content);
brakeparts.PartID = partid;
}
return brakeparts;
}
As I understand, you're simply trying to return a list of parts which you want to fill with the Parts breakparts that you deserialized from the Json response.
Simply create a List<Parts> instance and add the breakparts to it in the loop.
It could look like the following.
private static List<Parts> getBrakeparts(List<int> partids)
{
var restClient = new RestClient("https://example.example.net/api");
List<Parts> parts = new List<Parts>();
foreach (var partid in partids)
{
var returnreq = new RestRequest($"/brakeparts/{partid}/ ", Method.GET);
var res = restClient.Execute(returnreq);
Parts brakeparts = JsonConvert.DeserializeObject<Parts>(res.Content);
brakeparts.PartID = partid;
parts.Add(brakeparts);
}
return parts;
}
I have been using AutoMapper which I find really good.
But in current project I can't use AutoMapper because few reasons. lets not go into that.
Wondering if below is best way of manual mapping? Seems like it will be lot of looping depending on complexity of the model and one to many relationship.
Is there best or efficient way of doing manual mapping.
Basket basket = StoreRepository.GetBasket(BasketCode); // where BasketCode is xyz
List<ProductResponse> basketProducts = new List<ProductResponse>();
foreach (Product product in basket.Products) {
basketProducts.Add(new ProductResponse()
{
Name = product.Name,
Description = product.Description
});
}
BasketResponse result = new BasketResponse()
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basketProducts
};
return result;
Above is snippet from a method of Web API Controller which return Json.
I am using manual mapping to reduce detailed complexity and create required Json structure and data.
You would probably be better off creating some kind of general function for each class so you don't have to repeat the mapping everytime you want to use it. For example:
public static class Mapper
{
public static ProductResponse Map(Product product)
{
return new ProductResponse
{
Name = product.Name,
Description = product.Description
};
}
public static BasketResponse Map(Basket basket)
{
return new BasketResponse
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basket.Products.Select(a => Mapper.Map(a))
};
}
}
May be this question should be in code review. Anyway you can simplify your code by using Select LINQ query instead of FOREACH loop to build basketProducts list, like below.
List<ProductResponse> basketProducts = basket.Products.Select(product=> new ProductResponse()
{
Name = product.Name,
Description = product.Description
}).ToList();
You can simplify this further by writing a new delegate for mapping which can be reused at multiple places.
Func<Product, ProductResponse> MapProduct = delegate (Product product)
{
return new ProductResponse()
{
Name = product.Name,
Description = product.Description
};
};
then your code will be much simpler like below. Use the new delegate in SELECT method of LINQ query.
Basket basket = StoreRepository.GetBasket(BasketCode);
BasketResponse result = new BasketResponse()
{
BasketCode = basket.Code,
Description = basket.Description,
IntroMessage = basket.IntroMessage,
Products = basket.Products.Select(MapProduct).ToList()
};
return result;
The following code sample writes a simple object to a couchbase lite (version 2) database and reads all objects afterwards. This is what you can find in the official documentation here
This is quite a lot of manual typing since every property of every object must be transferred to the MutableObject.
class Program
{
static void Main(string[] args)
{
Couchbase.Lite.Support.NetDesktop.Activate();
const string DbName = "MyDb";
var db = new Database(DbName);
var item = new Item { Name = "test", Value = 5 };
// Serialization HERE
var doc = new MutableDocument();
doc.SetString("Name", item.Name);
doc.SetInt("Value", item.Value);
db.Save(doc);
using (var qry = QueryBuilder.Select(SelectResult.All())
.From(DataSource.Database(db)))
{
foreach (var result in qry.Execute())
{
var resultItem = new Item
{
// Deserialization HERE
Name = result[DbName].Dictionary.GetString("Name"),
Value = result[DbName].Dictionary.GetInt("Value")
};
Console.WriteLine(resultItem.Name);
}
}
Console.ReadKey();
}
class Item
{
public string Name { get; set; }
public int Value { get; set; }
}
}
From my research Couchbase lite uses JsonConvert internally, so there might be a way to simplify all that with the help of JsonConvert.
Anything like:
var json = JsonConvert.SerializeObject(item);
var doc = new MutableDocument(json); // No overload to provide raw JSON
or maybe
var data = JsonConvert.SerializeToDict(item); // JsonConvert does not provide this
var doc = new MutableDocument(data);
Is there or is this some kind of optimization and the preferred approach is by intend?
People ask about this quite often, but Couchbase Lite does not actually store JSON strings in the database. They are stored in a different format so this would not give the benefit that you think (the JSON would need to be reparsed and then broken down into the other format). I'd been pushing for a way to serialize classes directly instead of going through dictionary objects (which seems like the ultimate goal here) but our priority is on things that enterprise clients want and this doesn't seem to be one of them. Note that for it to make it in, it needs to be implemented in C# Java and Objective-C / Swift.
I don't know about JsonConvert but there seems to be a constructor that takes IDictionary<string, object> as argument. So I would try something like this (brain-compiled):
MutableDocument CreateDocument(object data)
{
if (data == null) return null;
var propertyValues = new Dictionary<string, object>();
foreach (var property in data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
propertyValues[property.Name] = property.GetValue(data);
}
return new MutableDocument(propertyValues);
}
See if this works.
I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};
This is the code which I'm not convinced. Please check how I'm passing as parameter the entity Collection.
public ExamProduced GetExamProduced(XElement xml)
{
var examProduced = new ExamProduced
{
ExamProducedID = (int)xml.Attribute("ExamID"),
Date = (DateTime)xml.Attribute("Date"),
Seed = (int)xml.Attribute("Seed"),
//Exercises = GetExercises(xml)
};
GetExercises(xml, examProduced.Exercises);
return examProduced;
}
public void GetExercises(XElement xml, EntityCollection<Exercise> entityCollection)
{
var objs =
from objective in xml.Descendants("Objective")
where (bool)objective.Attribute("Produced")
let id = (int)objective.Attribute("ID")
let id2 = (Objective)entityService.Objectives.Where(o => o.ObjectiveID == id).FirstOrDefault()
select new Exercise
{
Objective = id2,
MakeUp = ...
Quantify = ...
Score = ...
};
foreach (var exercise in objs)
{
entityCollection.Add(exercise);
}
}
If not, I'll receiving an error. Like this with this code.
public ExamProduced GetExamProduced(XElement xml)
{
var examProduced = new ExamProduced
{
ExamProducedID = (int)xml.Attribute("ExamID"),
Date = (DateTime)xml.Attribute("Date"),
Seed = (int)xml.Attribute("Seed"),
Exercises = GetExercises(xml)
};
return examProduced;
}
public EntityCollection<Exercise> GetExercises(XElement xml)
{
var objs =
from objective in xml.Descendants("Objective")
where (bool)objective.Attribute("Produced")
let id = (int)objective.Attribute("ID")
select new Exercise
{
ExerciseID = id,
MakeUp = (bool)objective.Attribute("MakeUp"),
Quantify = (byte)(int)objective.Attribute("Quantify"),
Score = (float)objective.Elements().Last().Attribute("Result")
};
var entityCollection = new EntityCollection<Exercise>();
foreach (var exercise in objs)
entityCollection.Add(exercise);
return entityCollection;
}
The error I am getting is below:
InvalidOperationException was unhandled.
The object could not be added to the EntityCollection or
EntityReference. An object that is attached to an ObjectContext cannot
be added to an EntityCollection or EntityReference that is not
associated with a source object.
I hope that from the comments I'm understanding you correctly... If not, I'll update this answer.
Firstly, your EntityCollection<Exercise> GetExercises(XElement xml) is not going to work. As the error message says, you cannot construct a random EntityCollection like that: the EntityCollection needs the object to be attached to the context because it automatically synchronises its list with the context. And since you aren't saying what to attach it to anywhere, it won't work. The only way to make it work would be to avoid creating an EntityCollection in the first place.
Your void GetExercises(XElement xml, EntityCollection<Exercise> entityCollection) procedure could work. However, you need to make sure to actually have an EntityCollection<Exercise> instance to be able to call it. The way you're creating your ExamProduced object, it isn't attached to the context by the time you return from GetExamProduced, so it isn't possible to have a EntityCollection<Exercise> property for it at that point.
Perhaps the easiest way to get things working would be to pass your context to the GetExamProduced method, and let them get attached to the context automatically. I'm assuming it's a common ObjectContext, but you can update it as needed:
public ExamProduced GetExamProduced(XElement xml, YourContext context)
{
var examProduced = new ExamProduced()
{
ExamProducedID = (int)xml.Attribute("ExamID"),
Date = (DateTime)xml.Attribute("Date"),
Seed = (int)xml.Attribute("Seed")
};
context.ExamsProduced.Attach(examProduced);
LoadExercises(xml, context, examProduced);
// examProduced.Exercises should be available at this point
return examProduced;
}
public void LoadExercises(XElement xml, YourContext context, ExamProduced examProduced)
{
foreach (var exercise in
from objective in xml.Descendants("Objective")
where (bool)objective.Attribute("Produced")
let id = (int)objective.Attribute("ID")
let id2 = (Objective)entityService.Objectives.Where(o => o.ObjectiveID == id).FirstOrDefault()
select new Exercise
{
ExamProduced = examProduced,
Objective = id2,
MakeUp = ...
Quantify = ...
Score = ...
}))
{
context.Exercises.Attach(exercise);
}
}
I don't know if these are new objects that should be added in the database, or if these objects are expected to exist in the database already. I've assumed the latter. If the former, .Attach should be updated to .AddObject in two places.
Is this what you're looking for, or did I misunderstand?