I want to assign a value in my DTO to another value in another table. I have tried the following below but does not seem to be working. I want to change the deleted value in the DTO.Option to the deleted value in the QuestionOptions table. My code is below:
private List<DTO.Option> MapOptions(List<DAL.QuestionOption> o)
{
List<DTO.Option> op = new List<DTO.Option>();
foreach (DAL.QuestionOption opt in o)
{
{
DTO.Option Option = MapOption(opt.Option);
foreach (var i in o)
{
Option.Deleted = i.isDeleted;
}
op.Add(Option);
}
}
return op;
}
private DTO.Option MapOption(DAL.Option o)
{
return new DTO.Option()
{
ID = o.ID,
Text = o.Text,
Value = o.Value
};
}
CODE UPDATED TO
private List<DTO.Option> MapOptions(List<DAL.QuestionOption> o)
{
List<DTO.Option> op = new List<DTO.Option>();
foreach (DAL.QuestionOption opt in o)
{
op.Add(MapOption(opt.Option));
}
return op;
}
private DTO.Option MapOption(DAL.QuestionOption o)
{
return new DTO.Option()
{
ID = o.Option.ID,
Text = o.Option.Text,
Value = o.Option.Value,
Deleted = o.isDeleted
};
}
You're looping through the List<DAL.QuestionOption> inside a loop of the List<DAL.QuestionOption>, and reassigning the Deleted property for every one of them. Unless I'm mistaken, that's not your intention. You'd be left with every DTO.Option.Deleted being equal to the DAL.QuestionOption.isDeleted of the last item in the list. I'm guessing DAL.QuestionOption looks approximately like this:
public class DAL.QuestionOption
{
public DAL.Option Option { get; set; }
public boolean isDeleted { get; set; }
}
public class DAL.Option
{
public int Id { get; set; }
public string Text { get; set; }
public string Value { get; set; }
}
If so, I would just change the MapOption to take in the DAL.QuestionOption instead of DAL.Option:
private DTO.Option MapOption(DAL.QuestionOption o)
{
return new DTO.Option()
{
ID = o.Option.ID,
Text = o.Option.Text,
Value = o.Option.Value,
Deleted = o.isDeleted
};
}
Related
Hello and still happy Ney Year
I would like to ask you for initial aid. My goal is to write a parser (e.g. source file is a bmecat-xml file and target is an Excel-file) that is dynamic and flexible enough to handle data-conversion even when sourcefile-content changes or user would require additional transformation of data.
I wrote the first part of the parser which loads data from the source-bmecat-file into corresponding classes. The class structure is exposed to the user (by reflection) and the user can map source-fields to target fields.
Where I get stuck is at the moment, when additional logic / conversion needs to be incorporated.
I think Scripting would help me to solve this. the mapping data (source field to target field) could contain an additional script that would be executed dynamically (and hence must have access to application data, especially classes which hold sourcefile and targetfile data).
It would be really great if you could point me to the right direction, to a point, where I can start from.
Thank you very much!
sample-code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace ScriptingDemoProject
{
class DataClass
{
TargetData target;
SourceData source;
MappingData map;
public DataClass()
{
target = new TargetData();
source = new SourceData();
map = new MappingData();
// generate sample data
GenerateData();
// copy source data to target data
ExecuteMapping();
}
public TargetData TargetDataInfo
{ get { return target; } }
public SourceData SourceDataInfo
{ get { return source; } }
public MappingData MappingDataInfo
{ get { return map; } }
private void GenerateData()
{
// add sourcedata
source.Header.DefaultLanguage = "deu";
source.RecipientID = "recipient...";
source.SenderID = "sender...";
SourceItem item = new SourceItem();
item.ItemID = "Item1";
item.ItemNames.AddRange( new List<SourceItemName>() {
new SourceItemName { ItemName = "Item1NameGerman", Languauge = "deu" },
new SourceItemName { ItemName = "Item1NameFrench", Languauge = "fra" }
});
source.Items.Add(item);
// add targetdata
target.AddRec(new List<TargetField>()
{
new TargetField { ColumnID=0, FieldName="ItemNo", FieldValue="Item1"},
new TargetField { ColumnID=1, FieldName="DescrGerman", FieldValue=""},
new TargetField { ColumnID=2, FieldName="DescrFrench", FieldValue=""}
});
target.AddRec(new List<TargetField>()
{
new TargetField { ColumnID=0, FieldName="ItemNo", FieldValue="Item2"},
new TargetField { ColumnID=1, FieldName="DescrGerman", FieldValue=""},
new TargetField { ColumnID=2, FieldName="DescrFrench", FieldValue=""}
});
// add mappinginstructions
map.TargetKeyFieldIndex = 0;
map.MappingFieldInfo.AddRange(new List<MappingFields>() {
new MappingFields { SourceFieldMapping="ItemName", TargetFieldMapping=1, ScriptMapping=#"... where Language=""ger""" },
new MappingFields { SourceFieldMapping="ItemName", TargetFieldMapping=2, ScriptMapping=#"... where Language=""fra""" }
});
// get properties, e.g.
var pInfo = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
}
private void ExecuteMapping()
{
// get target records
foreach (var targetRec in TargetDataInfo.TargetRecords)
{
// get key field value
string itemNo = targetRec.Where(x => x.ColumnID == map.TargetKeyFieldIndex).FirstOrDefault().FieldValue;
// get source item
SourceItem srcItem = SourceDataInfo.Items.Where(x => x.ItemID == itemNo).FirstOrDefault();
if (srcItem == null)
continue;
// get mapping instructions
foreach (var mapInstruction in map.MappingFieldInfo)
{
// i'd like to have two options
// option 1: use script
// option 2: use reflection
// option 1: script
// script will be executed at runtime and gets value from srcItem and sets value in targetRec
string script = mapInstruction.ScriptMapping;
// script would contain / execute the following statements:
TargetField field = targetRec.Where(x => x.ColumnID == mapInstruction.TargetFieldMapping).FirstOrDefault();
field.FieldValue = srcItem.ItemNames.Where(x => x.Languauge == "deu").FirstOrDefault().ItemName;
// option 2: get value by reflection
// e.g.
// though don't know how to handle List<Class>
PropertyInfo pi = SourceDataInfo.GetType().GetProperty("SenderID");
object val = pi.GetValue(SourceDataInfo, null);
// ...
}
}
}
}
public class MappingData
{
List<MappingFields> mappingFields;
public MappingData ()
{
mappingFields = new List<MappingFields>();
}
public int TargetKeyFieldIndex { get; set; }
public List<MappingFields> MappingFieldInfo
{ get { return mappingFields; } }
}
public class MappingFields
{
public string SourceFieldMapping { get; set; }
public int TargetFieldMapping { get; set; }
public string ScriptMapping { get; set; }
}
public class TargetData
{
private List<List<TargetField>> targetRecords;
public TargetData()
{
targetRecords = new List<List<TargetField>>();
}
public List<List<TargetField>> TargetRecords
{ get { return targetRecords; } }
public void AddRec(List<TargetField> TargetFields)
{
targetRecords.Add(TargetFields);
}
}
public class TargetField
{
public string FieldName
{ get; set; }
public int ColumnID
{ get; set; }
public string FieldValue
{ get; set; }
}
public class SourceData
{
private List<SourceItem> sourceItems;
private SourceHeader sourceHeader;
public SourceData()
{
sourceHeader = new SourceHeader();
sourceItems = new List<SourceItem>();
}
public SourceHeader Header
{ get { return sourceHeader; } }
public List<SourceItem> Items
{ get { return sourceItems; } }
public string SenderID
{ get; set; }
public string RecipientID
{ get; set; }
}
public class SourceHeader
{
public string DefaultLanguage
{ get; set; }
}
public class SourceItem
{
private List<SourceItemName> itemNames;
public SourceItem()
{
itemNames = new List<SourceItemName>();
}
public string ItemID
{ get; set; }
public List<SourceItemName> ItemNames
{ get { return itemNames; } }
public SourceItemName GetNameByLang(string Lang)
{
return itemNames.Where(x => x.Languauge == Lang).FirstOrDefault();
}
}
public class SourceItemName
{
public string ItemName
{ get; set; }
public string Languauge
{ get; set; }
}
}
I have an entity Contracts like this:
public partial class Contracts
{
public Contracts()
{
ListKindWorks = new HashSet<ListKindWorks>();
ListSubjects = new HashSet<ListSubjects>();
}
public int Id { get; set; }
public string Num { get; set; }
public DateTime DateConclusion { get; set; }
public int Worker { get; set; }
public DateTime DateStartWork { get; set; }
public DateTime DateEndWork { get; set; }
public float Salary { get; set; }
public virtual Workers WorkerNavigation { get; set; }
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
public virtual ICollection<ListSubjects> ListSubjects { get; set; }
}
And function ShowUpdateDialog():
/// <summary>
/// Open dialog for update chosen Contract
/// </summary>
/// <param name="c">chosen Contract</param>
internal void ShowUpdateDialog(Contracts c)
{
Contract = c;
using (ContractForm form = new ContractForm())
{
form.Fill(model.Data);
form.Fill(Contract);
form.Fill(model.GetUI(Mode.UPDATE));
if (form.ShowDialog() == DialogResult.OK)
{
bool result = true;
try
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
}
}
catch (Exception ex)
{
result = false;
string msg = string.Format("Ошибка во время обновления записи в базе данных. Детали: {0}", ex.Message);
form.ShowError(msg);
}
if (result)
{
ContractUpdatedSuccessEvent?.Invoke(this, EventArgs.Empty);
}
}
}
}
External variable:
public Contracts Contract { get; set; }
It is used not to allocate memory every time and is public, so that in case of a successful update another class can take it and insert into the DataGridView. Therefore I'm not accessing the database for the current values of the record, because the data comes from the DataGridView. To track changes used context.Attach(Contract).
internal Contracts GetMainValues(Contracts c)
{
c.Num = tbNum.Text;
c.Salary = float.Parse(tbSalary.Text);
c.DateConclusion = dpDateConclusion.Value;
c.DateStartWork = dpDateStart.Value;
c.DateEndWork = dpDateEnd.Value;
Item item = (Item)cbWorker.SelectedItem;
c.Worker = item.Id;
return c;
}
internal Contracts GetDetailValues(Contracts c)
{
listKindWorks.Clear();
listSelectedSubjects.Clear();
foreach (int index in clbKindWork.CheckedIndices)
{
int id = ((Item)clbKindWork.Items[index]).Id;
ListKindWorks item = new ListKindWorks
{
IdContract = c.Id,
IdKindWork = id
};
listKindWorks.Add(item);
}
foreach (Item item in lbSelectedSubject.Items)
{
ListSubjects subject = new ListSubjects
{
IdContract = c.Id,
IdSubject = item.Id
};
listSelectedSubjects.Add(subject);
}
c.ListKindWorks = listKindWorks;
c.ListSubjects = listSelectedSubjects;
return c;
}
My problem is as follows:
When if (.. == DialogResult.OK) is true, I need to update current Contract to new values from a form like this:
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
But therefore this code must be into using (ContractForm..). Otherwise impossible to get new values from form. If I create a new variable like Contracts and separate function Update like this:
private void Update(Contracts c)
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = c;
context.SaveChanges();
}
}
No update occurs for values from GetDetailValues(). Why?
Can I simplify this code?
Update:
According code from answer Henk Holterman and my private void Update(Contracts c):
changed values from GetMainValues(), but no from GetDetailValues()
I added to Contracts method Update() and call it after .Attach()
internal void Update(Contracts c)
{
this.Num = c.Num;
this.Salary = c.Salary;
this.Worker = c.Worker;
this.FullName = c.FullName;
this.DateConclusion = c.DateConclusion;
this.DateStartWork = c.DateStartWork;
this.DateEndWork = c.DateEndWork;
this.ListKindWorks = c.ListKindWorks;
this.ListSubjects = c.ListSubjects;
}
private void Update(Contracts oldValue, Contracts newValue)
{
using (ModelContext context = new ModelContext())
{
context.Attach(oldValue);
oldValue.Update(newValue);
// oldValue = newValue; // .Attach does not respond to this
context.SaveChanges();
}
}
I have tried a lot but all in vain.
I have written a LINQ code but not able to save changes in database.
It is giving no error neither it is updating record.
class Program
{
[Table(Name = "mainframe_replication")]
public class mainframe_replication
{
private string _REPL_GUID;
[Column(IsPrimaryKey = true, Storage = "_REPL_GUID")]
public string REPL_GUID
{
get { return this._REPL_GUID; }
set { this._REPL_GUID = value; }
}
private string _REPL_TYPE;
[Column(Storage = "_REPL_TYPE")]
public string REPL_TYPE
{
get { return this._REPL_TYPE; }
set { this._REPL_TYPE = value; }
}
private string _RPT_ID;
[Column(Storage = "_RPT_ID")]
public string RPT_ID
{
get { return this._RPT_ID; }
set { this._RPT_ID = value; }
}
private string _RPT_VERS;
[Column(Storage = "_RPT_VERS")]
public string RPT_VERS
{
get { return this._RPT_VERS; }
set { this._RPT_VERS = value; }
}
private string _RPT_BYTES;
[Column(Storage = "_RPT_BYTES")]
public string RPT_BYTES
{
get { return this._RPT_BYTES; }
set { this._RPT_BYTES = value; }
}
private string _REPL_DTM;
[Column(Storage = "_REPL_DTM")]
public string REPL_DTM
{
get { return this._REPL_DTM; }
set { this._REPL_DTM = value; }
}
private string _NOTIF_ID;
[Column(Storage = "_NOTIF_ID")]
public string NOTIF_ID
{
get { return this._NOTIF_ID; }
set { this._NOTIF_ID = value; }
}
}
public class MyPoco
{
public string ReportId { get; set; }
public string Reportversion { get; set; }
public string ReportBytes { get; set; }
public string ReportDate { get; set; }
public string NotifId { get; set; }
public string RecipAdd { get; set; }
}
public static string loglocation;
static void Main(string[] args)
{
try
{
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID, (mfr, nr)
=> new MyPoco { ReportId = mfr.RPT_ID, Reportversion = mfr.RPT_VERS, ReportBytes = mfr.RPT_BYTES.ToString(), ReportDate = mfr.REPL_DTM.ToString(), NotifId = mfr.NOTIF_ID, RecipAdd = nr.NOTIF_RECIP_ADDR });
foreach (var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "abc";
//DO STUFF
// repljoinmf_data.NotifId = "Changedxyz";
}
db.SubmitChanges();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
It is not giving any error while submitting changes.
What I need to change?
Any suggestion will be helpful.
If you want to save your changes back to the original data source, you need to be working with the actual entities instead of projections of those entities. Since you are joining two tables, one option is to put those instances into an anonymous type and update them:
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new {mfr, nr});
foreach (var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.mfr.NotifId = "Changedxyz";
}
db.SubmitChanges();
In your previous question you were told that anonymous types cannot be uptated, but in this case you're modifying instances that are referenced by the anonymous type. So you're not updating the anonymous type itself, just the objects that the anonymous type references.
You are modifying the property of your MyPoco object. This is just a representation of your table. That's why the database is not updated.
You can send your MyPoco to your client. It will perform some changes. Then you can recreate the entity and copy the properties from the Poco object. Then, you need to attach the modified entity to your table and then save the changes.
If you modify directly the entity, there is no need to attach, since it will have kept the links to the database (assuming you do that with the same Databasecontext).
,I have one class in which I have three properties now what I want to do, if in the object if any one of null or empty then I want to remove it from the object below is my code.
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
Now here I want the object of TestClass but in that Name and DateTime property should not be their in the object,
is it possible?
Please help me
There's no such concept as removing a property from an individual object. The type decided which properties are present - not individual objects.
In particular, it will always be valid to have a method like this:
public void ShowDateTime(TestClass t)
{
Console.WriteLine(t.DateTme);
}
That code has no way of knowing whether you've wanted to "remove" the DateTime property from the object that t refers to. If the value is null, it will just get that value - that's fine. But you can't remove the property itself.
If you're listing the properties of an object somewhere, you should do the filtering there, instead.
EDIT: Okay, no you've given us some context:
ok I am using Schemaless database so null and empty value also store space in database that's the reason
So in the code you're using which populates that database, just don't set any fields which corresponds to properties with a null value. That's purely a database population concern - not a matter for the object itself.
(I'd also argue that you should consider how much space you'll really save by doing this. Do you really care that much?)
I was bored and got this in LINQPad
void Main()
{
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
t.Dump();
var ret = t.FixMeUp();
((object)ret).Dump();
}
public static class ReClasser
{
public static dynamic FixMeUp<T>(this T fixMe)
{
var t = fixMe.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach(var pr in t.GetProperties())
{
var val = pr.GetValue(fixMe);
if(val is string && string.IsNullOrWhiteSpace(val.ToString()))
{
}
else if(val == null)
{
}
else
{
returnClass.Add(pr.Name, val);
}
}
return returnClass;
}
}
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
Hereby a 'slightly' more clear and shorter version of the accepted answer.
/// <returns>A dynamic object with only the filled properties of an object</returns>
public static object ConvertToObjectWithoutPropertiesWithNullValues<T>(this T objectToTransform)
{
var type = objectToTransform.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in type.GetProperties())
{
var value = propertyInfo.GetValue(objectToTransform);
var valueIsNotAString = !(value is string && !string.IsNullOrWhiteSpace(value.ToString()));
if (valueIsNotAString && value != null)
{
returnClass.Add(propertyInfo.Name, value);
}
}
return returnClass;
}
You could take advantage of the dynamic type:
class Program
{
static void Main(string[] args)
{
List<dynamic> list = new List<dynamic>();
dynamic
t1 = new ExpandoObject(),
t2 = new ExpandoObject();
t1.Address = "address1";
t1.ID = 132;
t2.Address = "address2";
t2.ID = 133;
t2.Name = "someName";
t2.DateTime = DateTime.Now;
list.AddRange(new[] { t1, t2 });
// later in your code
list.Select((obj, index) =>
new { index, obj }).ToList().ForEach(item =>
{
Console.WriteLine("Object #{0}", item.index);
((IDictionary<string, object>)item.obj).ToList()
.ForEach(i =>
{
Console.WriteLine("Property: {0} Value: {1}",
i.Key, i.Value);
});
Console.WriteLine();
});
// or maybe generate JSON
var s = JsonSerializer.Create();
var sb=new StringBuilder();
var w=new StringWriter(sb);
var items = list.Select(item =>
{
sb.Clear();
s.Serialize(w, item);
return sb.ToString();
});
items.ToList().ForEach(json =>
{
Console.WriteLine(json);
});
}
}
May be interfaces will be handy:
public interface IAdressAndId
{
int ID { get; set; }
string Address { get; set; }
}
public interface INameAndDate
{
string Name { get; set; }
DateTime? DateTime { get; set; }
}
public class TestClass : IAdressAndId, INameAndDate
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
Creating object:
IAdressAndId t = new TestClass()
{
Address = "address",
ID = 132,
Name = string.Empty,
DateTime = null
};
Also u can put your interfaces in separate namespace and make your class declaration as internal. After that create some public factories which will create the instances of your classes.
Item is not being remove from list
here is my code:
public interface IEmpConnection
{
int SegId { get; set; }
}
public class EmpConnection : IEmpConnection
{
private int segid;
public int SegId
{
get
{
return segid;
}
set
{
segid = value;
}
}
}
public class CustomerConnection : EmpConnection, ICustomerConnection
{
private int _id;
public int Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
}
public interface ICustomerConnection
{
int Id { get; set; }
}
public class CustConn : CustomerConnection
{
private ObservableCollection<CustomerConnection> _airSeg;
public CustConn()
{
_airSeg = new System.Collections.ObjectModel.ObservableCollection<CustomerConnection>();
_airSeg.Add(new AirSegmentConnection { Id = 1, SegId = 2 });
_airSeg.Add(new AirSegmentConnection { Id = 1, SegId = 3 });
}
private bool isDeleted;
public bool IsDeleted
{
get { return isDeleted; }
set { isDeleted = value; }
}
private List<IEmpConnection> _connection;
public List<IEmpConnection> Connections
{
get
{
var s = new AirSegmentConnection();
var k = s as ISegmentConnection;
if (IsDeleted)
{
_airSeg.RemoveAt(1);
}
return _connection = _airSeg.ToList().Cast<ISegmentConnection>().ToList();
//return _airSeg.ToList().Cast<ISegmentConnection>().ToList();
}
set
{
_connection = value;
//_airSeg = new System.Collections.ObjectModel.ObservableCollection<ISegmentConnection>(value.ToList()) ;
}
}
private ObservableCollection<CustomerConnection> airConnection;
public ObservableCollection<CustomerConnection> AirConnection
{
get { return _airSeg; }
set { _airSeg = value; }
}
}
on main
button click item is not being removed. please suggest me where i am doing wrong.
CustConn a = new CustConn();
if (a.Connections.Count > 0)
{
a.Connections = new List<IEmpConnection>();
a.Connections.RemoveAt(1);// this item is not being removed.
}
please suggest i am doing worng in this code.
Thanks
Amit
It seems that you are replacing the list of connections before you remove the connection.
Since you have this marked as WPF, I'm going to assume that at some point you were able to remove the item from the List, but it still appeared on the screen. Try this:
if (a.Connections.Count > 0)
{
var newList = new List<IEmpConnection>(a.Connections);
a.Connections.RemoveAt(1);
a.Connections = newList;
}
Alternatively, you may be able to use an ObservableCollection<IEmpConnection>. This is a special collection that raises events when the collection changes. Then you would simple remove the object, and the screen would update.
You're creating a new, empty list and then trying to remove an element at position 1. In fact you've just overwritten your original list.
if (a.Connections.Count > 0)
{
/// REMOVE THIS LINE a.Connections = new List<IEmpConnection>();
a.Connections.RemoveAt(1);// this item is not being removed.
}
The line I've commented out it creating a new list and overwriting a.Connections immediately before you try to remove the item. This is what's causing the code to fail.