I have a form, which shows three items in a combo box.
Continents, Countries and Cities
If I select an item, e.g. if I select Cities and then if I click on the "Get Results" button, I send a select command to the database via business and data layer which then retrieves a list of type Cities.
The List are then bound to the grid on the UI form.
The classes: Continents, Countries and Cities implement IEntities interface with property string "Name".
The button click event calls Business layer using:
click(object sender, EventArgs e)
{
string selectedItem = comboBox.SelectedItem;
IEntities entity = null;
List<IEntities> list = null;
if (selectedItem == "Cities")
{
entity = new Cities("City");
}
if (selectedItem == "Continents")
{
entity = new Continents("Continents");
}
if (selectedItem == "Countries")
{
entity = new Countries("Countries");
}
//Then I call a method in Business Layer to return list
BL bl = new BL(entity);
list = bl.GetItems();
myDataGrid.DataContext = list;//to bind grid to the list
}
Business Layer looks like this:
public class BL
{
public IEntities _entity;
//constructor sets the variable
public BL(IEntity entity)
{
_entity = entity;
}
public IList<Entities> GetItems()
{
//call a method in data layer that communicates to the database
DL dl = new DL();
return dl.CreateItemsFromDatabase(_entity.Name);//name decides which method to call
}
}
I want to use Unity as the IOC so instead of using factory (sort of) pattern in the button click event with if then elses and using hardcoded class names, I want to use the container's configration that creates the relevant class instance. And when the IEntities instance is passed to the constructor of the BL class, I want to pass the object using Unity. Can you please advice how to do it?
As it exists, this design is not well suited to incorporating an IoC container.
As long as your ComboBox still contains strings, you're going to have to compare that against hardcoded values in a switch statement or set of if blocks somewhere.
Furthermore, the BL class takes a constructor parameter of type IEntity, but that can be an object of any among many different types at runtime. There is no way to configure Unity at startup to instantiate BL without also telling it what to use as that parameter (and nothing to gain by it, really).
Interestingly, though, you seem to be instantiating these Entity objects for the sole purpose of passing their string name to the CreateItemsFromDatabase method; you're not using its type for anything. It seems that you can skip the constructor parameter altogether and simply pass the selected string from the ComboBox directly to the GetItems method and achieve the same result. If you have some other reason for doing this, you should at least not supply the name in the constructor; make it a const within each class declaration.
What might be better suited is to make GetItems a generic method. Instead of passing an IEntity to the BL constructor, you would pass the concrete type to the method:
var bl = new BL();
var countries = bl.GetItems<Countries>();
var cities = bl.GetItems<Cities>();
var continents = bl.GetItems<Continents>();
Related
In a view model's constructor I have a command declaration that calls a method:
OpenGroupCommand = new DelegateCommand(OnOpenGroupExecute);
And the method looks like:
private void OnOpenGroupExecute(object obj)
{
string groupName = (string)obj;
Application.Current.MainPage.Navigation.PushAsync(new GroupPage(groupName));
}
How can I test, that groupName is passed to another view model correctly? In another view model groupName parameter is sent to GroupName property on VM instance:
public class GroupPageViewModel : ViewModelBase, IGroupPageViewModel
{
private string _groupName;
public GroupPageViewModel(string groupName)
{
LoadGroupName(groupName);
}
public void LoadGroupName(string groupName)
{
GroupName = groupName;
}
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
OnPropertyChanged();
}
}
}
On debug all works fine, but how can I unit test it? Where can I read a bit about testing and mocking stuff like this, even with Moq framework?
I believe your question is actually about how to test navigation between pages.
In the implementation of method OnOpenGroupExecute, because you are using Xamarin forms stuff to implement the navigation, you have to refer Xamarin Forms assemblies in your test project which makes the unit test depend on Xamarin Forms.
As suggested in this document https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/ , try to create an interface for navigation and navigate with viewmodel (more details on https://github.com/dotnet-architecture/eShopOnContainers)
And in your unit test project, implement a fake navigation service class like below and inject into the DI container:
public class FakeNavigationService : INavigationService //this interface is from MS eShopOnContainer project
{
private List<ViewModelBase> _viewModels = new List<ViewModel>();
public Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase {
//create viewModel object from DI container
//var viewModel = ......
_viewModels.Add(viewModel);
}
public ViewModelBase CurrentPageViewModel {
get {
if (_viewModels.Count() < 1) {
return null;
}
return _viewModels[_viewModels.Count() - 1];
}
}
}
This is just a suggestion. If you have implemented most of features in your app, it takes time to change navigate-with-page to navigate-with-viewmodel.
Well, let's see what you have:
you have some code in a private method, unless you make that public you won't be able to test it directly, because you can't call it. I am not considering here any tricks that allow you to call private methods.
what does that method do? It is not clear at all, it receives an object, we don't know what's in it. You're converting it to string, but what if it is not a string? Can you convert that object to a string? who knows.
So we have a method, that we don't know what it does, we don't know what it receives as parameters, we can't call it directly, but we want to test it. This is not a good position to be in.
Step back a bit and ask yourself, what are you really trying to test?
You said : How can I test, that groupName is passed to another view model correctly?
what does "correctly" mean? You need to define what it means for that string to be correct. This will give a test scenario you can work with.
I expect to receive an object, which looks like A and I want to convert it to a string which looks like B. Forget about viewmodels for now, that's just unimportant noise.
You can change the method into a public one and you can test that for different types of input data, you're getting the right result. This is literally, working with an object and extract some stuff from it. When that method is correct, you can guarantee that the viewmodel will receive the right input and that is good enough from a unit testing point of view.
You can of course add more tests for various inputs, you can test for correct failure conditions etc.
I am creating some unit tests for a Country model object. This is partly-generated by the Linq-to-SQL mechanism from a database table and partly under my control. This class uses the CountryRepository for some checks when checking it is valid; particularly that a country of this name doesn't already exist in the database.
As one ought not to embroil oneself in the database during unit tests, I created a mock repository to provide pretend data, and modify the model class like this:-
public partial class Country
{
private ICountryRepository country_repository;
public Country(ICountryRepository passed_country_repository)
{
country_repository = passed_country_repository;
}
//...etc
I can then construct this object in the test like this:-
Country test_country = new Country(new MockCountryRepository())
{
// code in here
};
and the tests run satisfactorily.
The problem comes in actual live usage; I have to prefix every usage of the repository with this:-
if (country_repository == null)
{
country_repository = new CountryRepository();
}
as the country_repository variable is unset if the zero-parameter constructor is invoked. I originally had the declaration line reading:-
private ICountryRepository country_repository = new CountryRepository();
but that attempts a database connection whichever constructor is used. I can't change the zero-parameter constructor to set country_repository to anything because it is automatically-generated and my changes might disappear at zero notice.
Is there a better way of getting the MockCountryRepository into the model object? Or have I missed the point here somewhere, and if so, what should I be doing?
I want to store a temporary version of my Company model within WPF MVVM however I am having issues where even though the temp I create isn't bound to my UI elements, it is still being updated.
Here is what happens when the ModifyCompanyViewModel is instantiated:
public ModifyCompanyViewModel(Company passedCompany)
{
SelectedCompany = passedCompany;
_tempCompany = passedCompany;
CloseWindowCommand = new CloseableCommand<Window>(CloseWindow);
}
So I have a readonly Company named _tempCompany. The UI elements are bound like so:
<TextBox Grid.Row="1" Grid.Column="1" x:Name="NameTextBox" Text="{Binding SelectedCompany.Name, Mode=TwoWay}"/>
Clearly they're bound to the SelectedCompany. If I then type something different in the TextBox that contains the Company's Name, but return the _tempCompany the _tempCompany's name reflects that which I have typed.
How can I store the _tempCompany in a way that no matter what is typed it's name stays the same? I have started using this approach which works:
_tempCompany = new Company
{
Id = passedCompany.Id,
Name = passedCompany.Name
//Other properties..
};
But this seems very cumbersome and that I am overlooking an easier way.
The SelectedCompany property and the _tempCompany field reference the same Company object. If you want to store "a temporary version" of the Company object you need to create a temporary version, i.e. you need to create another instance of the Company class like you are currently doing:
_tempCompany = new Company
{
Id = passedCompany.Id,
Name = passedCompany.Name
//Other properties..
};
This is not cumbersome.
As suggested in the comments you could implement the ICloneable interface but this just moves the creation of the other instance to a method within the class that implements the interface. You still need to create another instance somewhere.
How can I implement ICloneable when the model is generated by EF?
Create a partial class and implement the Clone method in this one.
You have to create a viewmodel. Currently Company is a model. Attempting to use it as viewmodel (to bind to its properties) sooner or later will cause you problem, since you mention it's generated.
Consider a simple viewmodel wrapping Company:
public class CompanyViewModel: INotifyPropertyChanged
{
readonly Company _company;
public CompanyViewModel(Company company)
{
_company = company;
}
// now expose something
public string Address
{
get { return _company.Address }
set
{
// tracking changes
// note: you aren't tracking changes made to model instance!
_company.Address = value;
OnPropertyChanged();
}
}
// and here is what you actually want, read-only name
public string Name => _company.Name;
// you can optinally expose model and bind to it properties
// but that wouldn't let you track the changes
// unless model implements INotifyPropertyChanged
public Company Company => _company;
...
}
If you want to edit company name, then just make another property (call it NewName), set its initial value in constructor and decide for yourself when its value will replace _company.Name (e.g. in some method AcceptChanges() which will be called when user finish editing). You will be able to access both: NewName and not yet changed _company.Name to compare them and display confirmation button.
This has been bugging me for a while now, what I would like to be able to do is update an existing record on the database by making a change to the ObservableCollection or the record class SquirrelDataGridActiveView.
This is my DataAccessService:
public interface IDataAccessService
{
ObservableCollection<SquirrelDataGridActiveView> GetEmployees();
void UpdateRecord(SquirrelDataGridActiveView Emp);
int CreateEmployee(SquirrelDataGridActiveView Emp);
}
/// <summary>
/// Class implementing IDataAccessService interface and implementing
/// its methods by making call to the Entities using CompanyEntities object
/// </summary>
public class DataAccessService : IDataAccessService
{
Drive_SHEntities context;
public DataAccessService()
{
context = new Drive_SHEntities();
}
public ObservableCollection<SquirrelDataGridActiveView> GetEmployees()
{
ObservableCollection<SquirrelDataGridActiveView> Employees = new ObservableCollection<SquirrelDataGridActiveView>();
foreach (var item in context.SquirrelDataGridActiveViews)
{
Employees.Add(item);
}
return Employees;
}
public int CreateEmployee(SquirrelDataGridActiveView Emp)
{
context.SquirrelDataGridActiveViews.Add(Emp);
context.SaveChanges();
return Emp.ID;
}
public void UpdateRecord(SquirrelDataGridActiveView temp)
{
}
}
As you can see there is already a GetEmployees() method and a CreateEmployee() method however I'm finiding it very difficult to update the database with the new values.
Any suggestions would be much appreciated.
Looks like the problem maybe be in your EF layer. Do you have any unit tests to check that the creation of a new Employee record works properly? Can you break into the CreateEmployee and inspect the Emp.ID field? See if it's set to something. If it is, the creation of the new record works properly. One observation, if I may: your data access service does not need to return an ObservableCollection. I assume you already have an observable collection in your view-model class. If you want to keep alive the binding between the data grid in the view and the observable collection property in the view-model class, you should not reassign the OC property of the view-model class. The pattern you should follow is this:
return an IEnumeration from your data access service's GetEmployees() method;
Optional, but recommended is to make GetEmployees awaitable;
in your view-model class, clear the content of the OC property and then add, one by one, all the items in the IEnumeration collection returned by your GetEmployees() method. This way your binding will continue to work and any updates in the database will be reflected in the view's data grid.
You can keep the OC return from your GetEmployees, but in your view- model you still need to transfer all the items, one by one, into the property that is, most likely, bound to the data grid in the view. If you just assign the GetEmployees() returned OC list to the the view-model's property, your binding will be gone.
Perhaps your data grid does not refresh properly and that's why you conclude that the database is not updated when in fact it is.
HTH,
Eddie
Until now by Business Layer was instantiating one instance of my needed DAL objects:
public class BarcodeBLL : IBarcodeBLL
{
private BarcodeConfig _MyConfig;
private readonly IJDE8Dal _JDE8dal;
private readonly IBarcodeDal _barcodeDal;
public BarcodeBLL(BarcodeConfig MyConfig, ERPConfig erpConfig, BarcodeDALConfig barcodeDalConfig)
{
_MyConfig = MyConfig;
_JDE8dal = new JDE8Dal(erpConfig);
_barcodeDal = new BarcodeDAL(barcodeDalConfig);
}
...
...
}
A new set of front end applications need to access data on 4 different servers (SAME Data Access Layer implementation with 4 different connectionstrings).
One way is to let Ui instantiate 4 BarcodeBLL objects and do the job which i dont want in any case , because i would transfer business logic to UI.
So i have to find a proper way of instantiating from 1 to 4 DAL instances according to the UI application.
One thought is to pass a List<ERPConfig> and/or a List<BarcodeDALConfig> and let somewhow the contructor (???) decide what to do..
I started doing it like this:
public partial class BusinessLayer
{
private readonly Dictionary<string,IJDE8Dal> _JDE8dals;
public BusinessLayer(Dictionary<string,JDEDalConfig> jdeConfigs)
{
foreach (var j in jdeConfigs)
{
_JDE8dals.Add(j.Key,new JDE8Dal(j.Value));
}
}
}
This is what i am looking for..
Additional Info for clarity:
My goal as i see it now is for ONE method in BLL to be able to get from 1 to 4 DAL objects and execute methods in each of them.
Possible scenarions:
UI asks from BLL method GetItemList data from 2 countries.
Bll must unserstand somehow to create 2 DAL objects withg the correct connectionstring and do its job.
So i am consolidating operations for all my servers in the BLL and letting DAL to be alone.
Create an Enum, and modify your constructor to take a variable of the Enum?
Catch the incoming enum in init, and set a private property/variable.
Then inside your class, access the correct DAL based on the current selected enum.
from Business Layer
Dim d as new DAL(option1)
or
Dim d as new DAL(option2)
The solution i followed is this:
public partial class BusinessLayer
{
private readonly Dictionary<string,IJDE8Dal> _JDE8dals;
public BusinessLayer(Dictionary<string,JDEDalConfig> jdeConfigs)
{
foreach (var j in jdeConfigs)
{
_JDE8dals.Add(j.Key,new JDE8Dal(j.Value));
}
}
}
So the BLL layer will accept a dictionary of variable number of entries.
UI Application will be responsible to sent the dictionary so it is its own decision of how many DALs will be instantiated.
Moreover, BLL methods will be responsible to check for the existence of dictionary entries and act accordingly.