How to mock protected members with multiple interfaces - c#

How to mock this class in nUnit Tests?
public class OpenDataQuery: PagedQuery, IOpenDataQuery
{
private static Dictionary<string, SortItem> m_sortModes;
protected override Dictionary<string, SortItem> SortModes
{
get
{
if (m_sortModes == null)
{
m_sortModes = new Dictionary<string, SortItem>();
AddSortMode(m_sortModes, new SortItem(ObjectExtensions.GetNameFromExpression<OpenDataCategoriesModel, string>(m => m.Name), "Наименование ↑", true) { IsDefault = true });
AddSortMode(m_sortModes, new SortItem(ObjectExtensions.GetNameFromExpression<OpenDataCategoriesModel, string>(m => m.Name), "Наименование ↓"));
}
return m_sortModes;
}
}
public IEnumerable<OpenDataCategoriesModel> OpenDataCategories { get; set; }
public string OpenDataTags { get; set; }
}
and
public abstract class PagedQuery : IPagedQuery
{
private const int DEFAULT_PAGE = 1;
private const int DEFAULT_COUNT = 5;
private int? m_page;
private int? m_count;
private int? m_total;
private string m_sort;
public int? Page
{
get
{
if (m_page == null || m_page <= 0)
{
return DEFAULT_PAGE;
}
return m_page;
}
set { m_page = value; }
}
public int? Count
{
get
{
if (m_count == null || m_count <= 0)
{
return DEFAULT_COUNT;
}
return m_count;
}
set { m_count = value; }
}
public int? Total
{
get
{
if (m_total == null || m_total <= 0)
{
return 0;
}
return m_total;
}
set { m_total = value; }
}
public string SearchQuery { get; set; }
protected virtual Dictionary<string, SortItem> SortModes
{
get { return null; }
}
public string Sort
{
get
{
var sortMode = GetSortMode(m_sort);
if (sortMode == null)
{
var defaultSort = (from i in SortModes where i.Value.IsDefault select i).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(defaultSort.Key))
{
return defaultSort.Key;
}
return (from i in SortModes select i.Key).First();
}
return m_sort;
}
set
{
m_sort = value;
}
}
protected void AddSortMode(Dictionary<string, SortItem> sortModes, SortItem sortItem)
{
sortModes.Add(
String.Format(
"{0}{1}",
sortItem.FieldName.ToLower(),
sortItem.Asc ? "asc" : "desc"
),
sortItem
);
}
private SortItem GetSortMode(string sort)
{
if (SortModes == null || string.IsNullOrWhiteSpace(sort) ||
!SortModes.ContainsKey(sort.ToLower()))
{
return null;
}
return SortModes[sort.ToLower()];
}
public IOrderBy GetOrderBy()
{
var item = GetCurrentSortItem();
if (item == null)
{
return null;
}
if (item.Asc)
{
return new OrderBy(item.FieldName);
}
return new OrderByDesc(item.FieldName);
}
public SortItem GetCurrentSortItem()
{
return GetSortMode(Sort);
}
public Dictionary<string, SortItem> GetSortItems()
{
return SortModes;
}
}
and
public interface IOpenDataQuery : IPagedQuery
{
string OpenDataTags { get; set; }
}
I have some service method, that used openDataQuery class in parameters and in unit test i am trying mock this class, but this doesn't work:
public partial class OpenDataQueryRepository : Mock<OpenDataQuery>
{
public OpenDataQueryRepository(MockBehavior mockBehavior = MockBehavior.Strict)
: base(mockBehavior)
{
var opendataQuery = new Mock<IOpenDataQuery>();
var pagedQuery = opendataQuery.As<IPagedQuery>();
this.Setup(p=>p.GetOpenDataCategoriesMain(pagedQuery.Object,outttl)).Returns(OpenDataCategories);
}
}
I know that i should use Moq.Protected() for protected methods, but i don't know how use it correctly in this case. Please help me.
UPDATE:
I am testing this controller:
public class ODOpenDataController : ODBaseController
{
private readonly IOpenDataProvider m_openDataProvider;
public ODOpenDataController(IOpenDataProvider openDataProvider)
{
m_openDataProvider = openDataProvider;
}
public ActionResult Index(OpenDataQuery query)
{
int total;
query.OpenDataCategories = m_openDataProvider.GetOpenDataCategoriesMain(query, out total)
query.Total = total;
return View(query);
}
}
Test:
[Test]
public void Index_Test()
{
var opendataController = new ODOpenDataController(new OpenDataRepository().Object);
var result = opendataController.Index(new OpenDataQuery()) as ViewResult;
var model = result.Model as OpenDataQuery;
Assert.IsTrue(model.OpenDataCategories.Count() == 1);
}

Related

TinyMapper null checking in bind expression

Below are my classes
public class CommonClassSource
{
public int Id {get;set;}
}
public class CommonClassDestination
{
public int Id {get;set;}
}
public class SourceClass
{
public CommonClassSource CommonSource {get;set;}
}
public class DestinationClass
{
public CommonClassDestination CommonDestination {get;set;}
}
Is there any way to add null-checking in config.Bind? For example: here, check if source.CommonSource is null
TinyMapper.Bind<SourceClass, DestinationClass>(config => {
config.Bind(source => source.CommonSource.Id,
target => target.CommonDestination.Id));
});
If all you wanted to have the case handled that it there isn't an issue when source.CommonSource is null, the following script should work for you.
static bool isSourceNull;
public static void Main()
{
Func<SourceClass,object> getSCI = GetSourceClassId;
Func<DestinationClass, object> getDCI = GetDestClassId;
TinyMapper.Bind<SourceClass, DestinationClass>(config => {
config.Bind(source=>getSCI,
target =>getDCI);
});
}
static object GetSourceClassId(SourceClass source)
{
isSourceNull = source.CommonSource == null;
if (isSourceNull) return -1;
else return source.CommonSource.Id;
}
static object GetDestClassId(DestinationClass destinationClass)
{
if (isSourceNull)
{
destinationClass.CommonDestination = null;
return -1;
}
else if (destinationClass.CommonDestination != null)
return destinationClass.CommonDestination.Id;
else return -1;
}

loop over fields of a C# object

In a project there is a reporting class as follows:
public class ReportRowDataContract
{
public ReportDataDataContract ReportData1 { get; set; }
public ReportDataDataContract ReportData2 { get; set; }
public ReportDataDataContract ReportData3 { get; set; }
public ReportDataDataContract ReportData4 { get; set; }
public ReportDataDataContract ReportData5 { get; set; }
public ReportDataDataContract ReportData6 { get; set; }
}
Then there is a method that works with objects from the above class. Here is the first part of this method:
public ReportGrid(List<ReportRowDataContract> items , List<ReportDataDataContract> summaryData)
: base(items)
{
passedInSummaryData = summaryData;
if (items[0].ReportData1 != null)
{
if (items[0].ReportData1.DecimalValue != null)
{
Columns.Add(m => m.ReportData1.DecimalValue).Titled(items[0].ReportData1.Name).Encoded(false).
Sanitized(false).RenderValueAs(
m => (string.IsNullOrEmpty(#m.ReportData1.DisplayFormat)) ? Convert.ToDecimal(#m.ReportData1.DecimalValue).ToString("N") : Convert.ToDecimal(#m.ReportData1.DecimalValue).ToString(#m.ReportData1.DisplayFormat));
if (items[0].ReportData1.SumValue || items[0].ReportData1.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = items[0].ReportData1.Name,
AvgValue = items[0].ReportData1.AvgValue,
DecimalValue = 0
});
}
}
else if (items[0].ReportData1.IntValue != null)
{
Columns.Add(m => m.ReportData1.IntValue).Titled(items[0].ReportData1.Name);
if (items[0].ReportData1.SumValue || items[0].ReportData1.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = items[0].ReportData1.Name,
AvgValue = items[0].ReportData1.AvgValue,
IntValue = 0
});
}
}
else
{
Columns.Add(m => m.ReportData1.StringValue).Titled(items[0].ReportData1.Name);
}
}
if (items[0].ReportData2 != null)
{
if (items[0].ReportData2.DecimalValue != null)
{
Columns.Add(m => m.ReportData2.DecimalValue).Titled(items[0].ReportData2.Name).Encoded(false).
Sanitized(false).RenderValueAs(
m => (string.IsNullOrEmpty(#m.ReportData2.DisplayFormat)) ? Convert.ToDecimal(#m.ReportData2.DecimalValue).ToString("N") : Convert.ToDecimal(#m.ReportData2.DecimalValue).ToString(#m.ReportData1.DisplayFormat));
if (items[0].ReportData2.SumValue || items[0].ReportData2.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = items[0].ReportData2.Name,
AvgValue = items[0].ReportData2.AvgValue,
DecimalValue = 0
});
}
}
else if (items[0].ReportData2.IntValue != null)
{
Columns.Add(m => m.ReportData2.IntValue).Titled(items[0].ReportData2.Name);
if (items[0].ReportData2.SumValue || items[0].ReportData2.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = items[0].ReportData2.Name,
AvgValue = items[0].ReportData2.AvgValue,
IntValue = 0
});
}
}
else
{
Columns.Add(m => m.ReportData2.StringValue).Titled(items[0].ReportData2.Name);
}
}
This method consists of code that repeats itself out to ReportData6, changing only the ReportData field name with each repetition. Is there a way that this method can be rewritten to process each ReportData field by looping somehow? Besides making for a shorter method, this would be extremely useful to have in order to avoid manually updating the method if additional ReportData fields need to be added to the ReportRowDataContract class in the future.
Edit #1: I am fairly new to C# so detailed answers of how to go about this would be immensely helpful.
Edit #2: Thanks to Zohar Peled's post below, the following code feels very close. However, m.ReportData1 is causing problems in the AddGridColumn() method. The error message is 'ReportRowDataContract' does not contain a definition for 'item'...
I tried passing in ReportData 1 as a second argument when AddGridColumn() is called, but to no avail. Is there a way to modify the code so it works?
code that calls method:
// create columns for grid
AddGridColumn(items[0].ReportData1);
AddGridColumn(items[0].ReportData2);
AddGridColumn(items[0].ReportData3);
AddGridColumn(items[0].ReportData4);
AddGridColumn(items[0].ReportData5);
AddGridColumn(items[0].ReportData6);
method:
private void AddGridColumn(ReportDataDataContract item)
{
if (item != null)
{
if (item.DecimalValue != null)
{
Columns.Add(m => m.ReportData1.DecimalValue).Titled(item.Name).Encoded(false).
Sanitized(false).RenderValueAs(
m => (string.IsNullOrEmpty(#m.ReportData1.DisplayFormat)) ?
Convert.ToDecimal(#m.ReportData1.DecimalValue).ToString("N") :
Convert.ToDecimal(#m.ReportData1.DecimalValue).ToString(#m.ReportData1.DisplayFormat));
if (item.SumValue || item.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = item.Name,
AvgValue = item.AvgValue,
DecimalValue = 0
});
}
}
else if (item.IntValue != null)
{
Columns.Add(m => m.ReportData1.IntValue).Titled(item.Name);
if (item.SumValue || item.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = item.Name,
AvgValue = item.AvgValue,
IntValue = 0
});
}
}
else
{
Columns.Add(m => m.ReportData1.StringValue).Titled(item.Name);
}
}
}
Edit #3: This is the ReportDataDataContract class definiton:
public class ReportDataDataContract
{
public string Name { get; set; }
public string StringValue { get; set; }
public decimal? DecimalValue { get; set; }
public int? IntValue { get; set; }
public bool SumValue { get; set; }
public bool AvgValue { get; set; }
public int? Index { get; set; }
public string DisplayFormat { get; set; }
}
Can you add an indexed property like this to ReportRowDataContract in order to essentially access the ReportData values as an indexed property?
public ReportDataDataContract this[int i]
{
get
{
return new ReportDataDataContract[] { ReportData1, ReportData2, ReportData3, ReportData4, ReportData5, ReportData6 }[i];
}
}
The you can use items[0][i].SumValue, for example, instead of items[0].ReportData1.SumValue.
If you can, you should simply change the ReportRowDataContract to only hold a single property that is an array of ReportDataDataContract. Then you can use a simple loop for each of the data contracts.
If you can't change the ReportRowDataContract table, you could use a method that takes in an argument of type ReportDataDataContract and have all the repeated code there - and just call it one time for each property.
The method should look something like that (based on the code you've posted):
void DoSomething(ReportDataDataContract dataContranct)
{
if (dataContranct != null)
{
if (dataContranct.DecimalValue != null)
{
Columns.Add(m => dataContranct.DecimalValue).Titled(dataContranct.Name).Encoded(false).
Sanitized(false).RenderValueAs(
m => (string.IsNullOrEmpty(#dataContranct.DisplayFormat)) ?
Convert.ToDecimal(#dataContranct.DecimalValue).ToString("N") :
Convert.ToDecimal(#dataContranct.DecimalValue).ToString(#dataContranct.DisplayFormat));
if (dataContranct.SumValue || dataContranct.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = dataContranct.Name,
AvgValue = dataContranct.AvgValue,
DecimalValue = 0
});
}
}
else if (dataContranct.IntValue != null)
{
Columns.Add(m => dataContranct.IntValue).Titled(dataContranct.Name);
if (dataContranct.SumValue || dataContranct.AvgValue)
{
displaySummary = true;
SummaryData.Add(
new ReportDataDataContract
{
Name = dataContranct.Name,
AvgValue = dataContranct.AvgValue,
IntValue = 0
});
}
}
else
{
Columns.Add(m => mdataContranct.StringValue).Titled(dataContranct.Name);
}
}
}

WCF calls twice or more itself, but only if I keep a code line (I need it)

I have a weird problem. I've made a couple of working wcf. I've updated one of them and it seems all ok.
But, if I call a method with a get within the browser, I get ERR_CONNECTION_RESET. Debbuging it, I've found that the code is looping, calling itself twice or three times, when the call is only one.
The code is really similar to other, but there is something I can't understand.
Why does it loop?
This is the code of my method:
public List<WrapImpianti> GetImpianto(string codret, string storeID, string hashedString, string outputType)
{
Utility.Logger("GetImpianto: start " + outputType);
var md5 = new md5Manager();
string key = "";
IS_RETISTI retista = getRetista(codret);
if (retista != null)
key = retista.CHIAVEDES;
List<WrapImpianti> r = new List<WrapImpianti>();
//return r;
if (md5.checkHashedInput(codret + storeID, hashedString, key))
{
try
{
using (var db = new AccessData.Entities())
{
var t = db.IS_IMPIANTI.Where(x => x.STOREID == storeID && x.IDRET == retista.ID).ToList();
r = t.Select(x => new WrapImpianti(x, key)).ToList();
}
return r;
}
catch (Exception ex)
{
throw new WebFaultException<string>(ex.Message, HttpStatusCode.Conflict);
}
}
else
throw new WebFaultException<string>("Hash non corretto", HttpStatusCode.BadRequest);
}
If I comment the row "r = t.Select(x => new WrapImpianti(x, key)).ToList();", it works... or, at least, it returns an empty object (because I don't populate it) without looping.
Why? It only calls the init method of my class WrapImpianti...
this is the class
[DataContract]
public class WrapImpianti
{
public WrapImpianti(){}
private IS_IMPIANTI model;
private string key;
public WrapImpianti(IS_IMPIANTI model, string key)
{
this.model = model;
this.key = key;
}
private string p_STOREID { get; set; }
[DataMember]
public string STOREID
{
get
{
if (model == null)
return p_STOREID.ToSafeString();
else
return this.model.STOREID.ToSafeString();
}
set { p_STOREID = value; }
}
private string p_CODICE { get; set; }
[DataMember]
public string CODICE
{
get
{
if (model == null)
return p_CODICE.ToSafeString();
else
return this.model.CODICE.ToSafeString();
}
set { p_CODICE = value; }
}
private string p_CODRETE { get; set; }
[DataMember]
public string CODRETE
{
get
{
if (model == null)
return p_CODRETE.ToSafeString();
else
{
using (var db = new AccessData.Entities())
{
var pp = db.IS_RETISTI.FirstOrDefault(x => x.ID == this.model.IDRET);
if (pp != null)
return pp.CODICE;
else
return "";
}
}
}
set { p_CODRETE = value; }
}
private string p_INDIRIZZO { get; set; }
[DataMember]
public string INDIRIZZO
{
get
{
if (model == null)
return p_INDIRIZZO.ToSafeString();
else
return this.model.INDIRIZZO.ToSafeString();
}
set { p_INDIRIZZO = value; }
}
private string p_CITTA { get; set; }
[DataMember]
public string CITTA
{
get
{
if (model == null)
return p_CITTA.ToSafeString();
else
return this.model.CITTA.ToSafeString();
}
set { p_CITTA = value; }
}
private string p_STATO { get; set; }
[DataMember]
public string STATO
{
get
{
if (model == null)
return p_STATO.ToSafeString();
else
return this.model.STATO.ToSafeString();
}
set { p_STATO = value; }
}
private string p_COD_ESERCENTE { get; set; }
[DataMember]
public string COD_ESERCENTE
{
get
{
if (model == null)
return p_COD_ESERCENTE.ToSafeString();
else
return this.model.COD_ESERCENTE.ToSafeString();
}
set { p_COD_ESERCENTE = value; }
}
private string p_TERMINAL_ID { get; set; }
[DataMember]
public string TERMINAL_ID
{
get
{
if (model == null)
return p_TERMINAL_ID.ToSafeString();
else
return this.model.TERMINAL_ID.ToSafeString();
}
set { p_TERMINAL_ID = value; }
}
private string p_COL { get; set; }
[DataMember]
public string COL
{
get
{
if (model == null)
return p_COL.ToSafeString();
else
return this.model.COL.ToSafeString();
}
set { p_COL = value; }
}
private string p_NOME { get; set; }
[DataMember]
public string NOME
{
get
{
if (model == null)
return p_NOME.ToSafeString();
else
return this.model.NOME.ToSafeString();
}
set { p_NOME = value; }
}
private string p_CAP { get; set; }
[DataMember]
public string CAP
{
get
{
if (model == null)
return p_CAP.ToSafeString();
else
return this.model.CAP.ToSafeString();
}
set { p_CAP = value; }
}
private string p_TELUFF { get; set; }
[DataMember]
public string TELUFF
{
get
{
if (model == null)
return p_TELUFF.ToSafeString();
else
return this.model.TELUFF.ToSafeString();
}
set { p_TELUFF = value; }
}
private string p_TELCELL { get; set; }
[DataMember]
public string TELCELL
{
get
{
if (model == null)
return p_TELCELL.ToSafeString();
else
return this.model.TELCELL.ToSafeString();
}
set { p_TELCELL = value; }
}
private string p_NOTE { get; set; }
[DataMember]
public string NOTE
{
get
{
if (model == null)
return p_NOTE.ToSafeString();
else
return this.model.NOTE.ToSafeString();
}
set { p_NOTE = value; }
}
private string p_PIVA { get; set; }
[DataMember]
public string PIVA
{
get
{
if (model == null)
return p_PIVA.ToSafeString();
else
return this.model.PIVA.ToSafeString();
}
set { p_PIVA = value; }
}
private string p_CODICEFISCALE { get; set; }
[DataMember]
public string CODICEFISCALE
{
get
{
if (model == null)
return p_CODICEFISCALE.ToSafeString();
else
return this.model.CODICEFISCALE.ToSafeString();
}
set { p_CODICEFISCALE = value; }
}
private string p_GESTORE { get; set; }
[DataMember]
public string GESTORE
{
get
{
if (model == null)
return p_GESTORE.ToSafeString();
else
{
using (var db = new AccessData.Entities())
{
return db.IS_GESTORI.FirstOrDefault(x => x.ID == this.model.IDGES).CODICE.ToSafeString();
}
}
}
set { p_GESTORE = value; }
}
private string p_PROPRIETARIO { get; set; }
[DataMember]
public string PROPRIETARIO
{
get
{
if (model == null)
return p_PROPRIETARIO.ToSafeString();
else
{
using (var db = new AccessData.Entities())
{
return db.IS_PROPRIETARI.FirstOrDefault(x => x.ID == this.model.IDPRP).CODICE.ToSafeString();
}
}
}
set { p_PROPRIETARIO = value; }
}
}
Why, if I call my class init method, does it start looping? And then, why does it return ERR_CONNECTION_RESET?
Ok, this is interesting. The solutions was here:
public string PROPRIETARIO
{
get
{
if (model == null)
return p_PROPRIETARIO.ToSafeString();
else
{
using (var db = new AccessData.Entities())
{
return db.IS_PROPRIETARI.FirstOrDefault(x => x.ID == this.model.IDPRP).CODICE.ToSafeString();
}
}
}
set { p_PROPRIETARIO = value; }
in my customclass.. sometimes, the IDPRP is null and raises this error.
It is very interisting: I was expecting this type of error was more visible to the developer, instead of loop itself and get an anonymous error.
Hope it can be useful for someone. ;)

Entity Framework 6.1: CRUD on Child objects

I populate a data grid with a list of objects that come from a repository like this:
public static IEnumerable<Order> GetOrdersForDataGrid()
{
IEnumerable<Order> query;
using (RSDContext = new RSDContext())
{
query = context.Orders.Include(o=>o.OrderDetails).ToList();
}
return query;
}
When I want to edit an order I pass the selected row to a new window like this:
OrderEditWindow orderEdit = new OrderEditWindow();
orderEdit.SelectedOrder = SelectedOrder;
orderEdit.ShowDialog();
Here I set the DataContext of the Window to:
DataContext = SelectedOrder;
In this window I have another data grid that binds to OrderDetails collection property of Order. The problem is on CRUD operations on OrderDetails. For example, after I add a new orderDetail like this:
private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
{
if (!ValidateProductDetail())
return;
var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
OrderDetail orderDetail = new OrderDetail();
orderDetail.Price = selectedProduct.Price;
orderDetail.ProductCode = selectedProduct.Code;
orderDetail.ProductName = selectedProduct.Name;
orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Um = selectedProduct.Um;
orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
orderDetail.Group = selectedProduct.Subgroup.Group.Name;
orderDetail.Subgroup = selectedProduct.Subgroup.Name;
orderDetail.SupplierName = selectedProduct.Supplier.Name;
//orderDetail.Order=SelectedOrder;
//orderDetail.OrderId = SelectedOrder.OrderId;
SelectedOrder.OrderDetails.Add(orderDetail);
ProductAutoCompleteBox.Text = string.Empty;
QuantityNumericUpDown.Value = 1;
ProductAutoCompleteBox.Focus();
}
and then I call the update method from repository:
public static void UpdateOrder(Order order)
{
using (RSDContext context = new RSDContext())
{
context.Orders.Attach(order);
context.Entry(order).State = EntityState.Modified;
context.SaveChanges();
}
}
I get an error about OrderId. If i set manualy the navigation property and the id I don't get an error but changes dont get saved into db.
My Order model look like this:
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Order()
{
_OrderDetails = new ObservableCollection<OrderDetail>();
_OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
}
void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
if (e.OldItems != null)
CalcualteTotals();
}
[NotMapped]
public decimal CalculatedTotal
{
get
{
return OrderDetails.Sum(x => x.Total);
}
}
public int OrderId { get; set; }
private int _Number;
public int Number
{
get { return _Number; }
set
{
_Number = value;
NotifyPropertyChanged("Number");
}
}
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set
{
_Date = value;
NotifyPropertyChanged("Date");
}
}
private bool _Canceled;
public bool Canceled
{
get { return _Canceled; }
set
{
_Canceled = value;
NotifyPropertyChanged("Canceled");
}
}
private string _ClientName;
public string ClientName
{
get { return _ClientName; }
set
{
_ClientName = value;
NotifyPropertyChanged("ClientName");
}
}
private string _ClientPhone;
public string ClientPhone
{
get { return _ClientPhone; }
set
{
_ClientPhone = value;
NotifyPropertyChanged("ClientPhone");
}
}
private string _DeliveryAddress;
public string DeliveryAddress
{
get { return _DeliveryAddress; }
set
{
_DeliveryAddress = value;
NotifyPropertyChanged("DeliveryAddress");
}
}
private decimal _Transport;
public decimal Transport
{
get { return _Transport; }
set
{
_Transport = value;
NotifyPropertyChanged("Transport");
}
}
private decimal _Total;
public decimal Total
{
get { return _Total; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
private ObservableCollection<OrderDetail> _OrderDetails;
public virtual ObservableCollection<OrderDetail> OrderDetails
{
//get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
get
{
return _OrderDetails;
}
set
{
_OrderDetails = value;
NotifyPropertyChanged("OrderDetails");
}
}
private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
{
foreach (var p in orderDetails)
{
p.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "Quantity":
case "Price":
case "Total":
CalcualteTotals();
break;
}
};
}
CalcualteTotals();
}
public void CalcualteTotals()
{
NotifyPropertyChanged("CalculatedTotal");
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
And my OrderDetail model look like this:
public class OrderDetail : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int OrderDetailId { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
private int _ProductCode;
public int ProductCode
{
get { return _ProductCode; }
set
{
_ProductCode = value;
NotifyPropertyChanged("ProductCode");
}
}
private string _ProductName;
public string ProductName
{
get { return _ProductName; }
set
{
_ProductName = value;
NotifyPropertyChanged("ProductName");
}
}
private string _Um;
public string Um
{
get { return _Um; }
set
{
_Um = value;
NotifyPropertyChanged("Um");
}
}
private decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
_Price = value;
NotifyPropertyChanged("Price");
NotifyPropertyChanged("Total");
}
}
private int _Quantity;
public int Quantity
{
get { return _Quantity; }
set
{
_Quantity = value;
NotifyPropertyChanged("Quantity");
NotifyPropertyChanged("Total");
}
}
private string _SupplierName;
public string SupplierName
{
get { return _SupplierName; }
set
{
_SupplierName = value;
NotifyPropertyChanged("SupplierName");
}
}
private string _Subgroup;
public string Subgroup
{
get { return _Subgroup; }
set
{
_Subgroup = value;
NotifyPropertyChanged("Subgroup");
}
}
private string _Group;
public string Group
{
get { return _Group; }
set
{
_Group = value;
NotifyPropertyChanged("Group");
}
}
public decimal _Total;
public decimal Total
{
get { return Quantity * Price; }
set
{
_Total = value;
NotifyPropertyChanged("Total");
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
I'm really trying to use some sort of unit of work and I don't understand how i'm supposed to apply CRUD on objects with child collections and keep the UI updated in the same time (by working in a ObservableCollection and using Binding ClientPhone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged my parent window is updated as I type)
A final working solution:
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
List<int> OriginalOrderDetailsIds =
context.OrderDetails.Where(o => o.OrderId == order.OrderId).Select(o => o.OrderDetailId).ToList();
List<int> CurrentOrderDetailsIds = details.Select(o => o.OrderDetailId).ToList();
List<int> DeletedOrderDetailsIds = OriginalOrderDetailsIds.Except(CurrentOrderDetailsIds).ToList();
context.Entry(order).State = EntityState.Modified;
foreach (var deletedOrderDetailId in DeletedOrderDetailsIds)
{
context.Entry(context.OrderDetails.Single(o => o.OrderDetailId == deletedOrderDetailId)).State = EntityState.Deleted;
}
foreach (OrderDetail detail in details)
{
// Add.
if (detail.OrderDetailId == 0)
{
detail.OrderId = order.OrderId;
context.Entry(detail).State = EntityState.Added;
}
// Update.
else
{
context.Entry(detail).State = EntityState.Modified;
}
}
context.SaveChanges();
}
You could do this way for adding and updating the child, but not sure about deleted order details in the ui. If you don't want to get the order from entity, you need some kind of marking in the OrderDetail for deleted OrderDetail.
using (RSDContext context = new RSDContext())
{
var details = order.OrderDetails;
order.OrderDetails = null;
context.Entry(order).State = EntityState.Modified;
foreach (var detail in details)
{
if (detail.Id == 0)
{
// Adds.
detail.OrderId = order.Id;
context.Entry(detail).State = EntityState.Added;
}
else if (detail.IsDeleted)
// Adds new property called 'IsDeleted'
// and add [NotMapped] attribute
// then mark this property as true from the UI for deleted items.
{
// Deletes.
context.Entry(detail).State = EntityState.Deleted;
}
else
{
// Updates.
context.Entry(detail).State = EntityState.Modified;
}
}
order.OrderDetails = details;
context.SaveChanges();
}

what is the best way to dynamicly load classes and invoke them

This is what I came up with, but it feels bloated and well, untidy. And I don't like that I have created an instance of each class just to get the right one.
class FileHasher
{
private readonly List<IHasher> _list;
public FileHasher()
{
_list = new List<IHasher>();
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
if(typeof(IHasher).IsAssignableFrom(type) && type.IsClass)
_list.Add((IHasher) Activator.CreateInstance(type));
}
}
public HashReturn GetHashFromFile(string file, HashFileType hashType)
{
var hashReturn = new HashReturn();
IHasher iHasher = _list.Find(hasher => hasher.HashType == hashType);
hashReturn.Hash = iHasher.FileToHash(file);
return hashReturn;
}
public HashReturn GetHashFromString(string str, HashFileType hashType)
{
var hashReturn = new HashReturn();
IHasher iHasher = _list.Find(hasher => hasher.HashType == hashType);
hashReturn.Hash = iHasher.StringToHash(str);
return hashReturn;
}
}
internal class HashReturn
{
public Exception Error { get; set; }
public string Hash { get; set; }
public bool Success { get; set; }
}
enum HashFileType
{
CRC32,
MD5
}
internal interface IHasher
{
HashFileType HashType { get; }
string FileToHash(string file);
string StringToHash(string str);
}
class MD5Hasher : IHasher
{
public HashFileType HashType { get { return HashFileType.MD5; } }
public string FileToHash(string file)
{
return "";
}
public string StringToHash(string str)
{
return "";
}
}
class CRC32Hasher : IHasher
{
public HashFileType HashType { get { return HashFileType.CRC32; } }
public string FileToHash(string file)
{
return "";
}
public string StringToHash(string str)
{
return "";
}
}
MEF solves this nicely for you.
http://mef.codeplex.com/
It is included in .NET 4.

Categories

Resources