I am working on a project in C# using Entity Framework. Using EF, I connect to database that has a dozen of tables, and none of the views.
What I want to accomplish is create object in code that would represent sql view (i.e. three DB tables joined for presenting useful data).
I need this so I could create binding data source for the datagirdview. Right now I manually wrote SQL query for joining three tables and creating a list which then I define as datagridview.DataSource
This troubles me because of hard design about presenting the data in the datagridview. I have to manually write everything in code, and also not sure how to accomplish everything I need.
I would be more satisfied if I could create new class that would represent above and then in Designer View add Data source as object and view it in Designer mode and edit columns right there.
My query which does the job is as follows:
using (var context = new csModelEntitites())
{
var listaVozila = (from voz in context.Vozilo
join var in context.Varijanta on voz.VarijantaID equals var.ID
join mod in context.Model on var.ModelID equals mod.ID
join mar in context.Marka on mod.MarkaID equals mar.ID
select new
{
voz.ID,
voz.VIN,
Vozilo = mar.Naziv + " " + mod.Naziv + " " + var.Motor,
voz.GodProizvodnje,
voz.RegOznaka,
voz.RegDo
}).ToList();
VozilaPrikaz.DataSource = null;
VozilaPrikaz.DataSource = listaVozila;
foreach (DataGridViewColumn c in VozilaPrikaz.Columns)
{
if (c.HeaderText == "GodProizvodnje")
c.HeaderText = "Godina proizvodnje";
if (c.HeaderText == "RegOznaka")
c.HeaderText = "Registarska oznaka";
if (c.HeaderText == "RegDo")
c.HeaderText = "Registriran do";
I want to create class that would do the similar. Any help appreciated.
You can bind a user defined custom class to a datagridview and edit the column headers in the designer-view. The steps would be.
First create the class whose public properties you would want as the datagridview column name. For example I created the class Class1.cs in my project folder. Later on , you can edit the column header or other related property in the designer.
namespace WindowsFormsApp2
{
public class Class1
{
public string x1 { get; set; }
public string x2 { get; set; }
public Class1(string x1, string x2)
{
this.x1 = x1;
this.x2 = x2;
}
}
}
Next in the designer view, pull an empty DataGridView from the ToolBox.
Right click on the DataGridView->Properties->DataSource->Add Project DataSource ->
Then in the dialog box, choose "Object" as "Data Source Type".
Then under "Select the data Objects" if you expand the tree , you would see your class.
In my case, I select "Class1" , the same class which I had earlier created.
Then using edit columns, you can change any header text or so.
In the code file, the data needs to be filled in as below:
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
private BindingSource bindingSource1 = new BindingSource();
public Form1()
{
InitializeComponent();
bindingSource1.Add(new Class1("gdc1", "gdc2"));
dataGridView1.DataSource = bindingSource1;
}
}
}
That's the . The datagridView is all set.
Related
I have two comboboxes (CMBIDCAT) for Id of categories of product and (CMBCATNAME) for name of categories of product. When I choose the Id of category from (CMBIDCAT) combobox, I want to show the name of that chosen category in (CMBCATNAME) combobox. I use a SQL database and I use a class to access the data, stored procedure to fill comboboxes, textboxes etc., and folders to organize my work.
I organize my work with folders and classes like this
The following code used to fill data into my comboboxes:
public partial class ADD_PRODUCT_FORM : Form
{
BL.CLS_PRODUCTS prd = new BL.CLS_PRODUCTS();
public ADD_PRODUCT_FORM()
{
InitializeComponent();
CMBIDCAT.DataSource = prd.GET_ID_CATEGORIES();
CMBIDCAT.DisplayMember = "ID_CAT";
CMBIDCAT.ValueMember = "ID_CAT";
CMBCATNAME.DataSource = prd.GET_ID_CATEGORIES();
CMBCATNAME.DisplayMember = "CAT_NAME";
CMBCATNAME.ValueMember = "CAT_NAME";
}
}
I hope someone can explain my problem by appropriate form.
I don't see any reason why you would need two comboBoxes? Instead you better use one comboBox which shows the Id and Name like this:
public partial class ADD_PRODUCT_FORM : Form
{
BL.CLS_PRODUCTS prd = new BL.CLS_PRODUCTS();
public ADD_PRODUCT_FORM()
{
InitializeComponent();
CMBIDCAT.DataSource = prd.GET_ID_CATEGORIES();
CMBIDCAT.DisplayMember = "CAT_NAME";
CMBIDCAT.ValueMember = "ID_CAT";
}
}
This will show one comboBox. If you open it (or select a value) you see the Id and the corresponding name. You can access the selected value like this:
private void GetComboValue()
{
var value = CMBIDCAT.SelectedItem as DataRowView;
if (value != null)
{
int id = value["ID_CAT"];
string name = value["CAT_NAME"];
}
//OR if you just need Id
int id = Convert.ToInt(CMBIDCAT.SelectedValue);
}
Expect that you DataSource is a DataTable.
I'm new to databases and I'm not sure how to handle this situation. I have 3 tables connected this way:
Session <- 1:1 -> Document <- 1:1 -> DocumentData
So basically there is always 1 Session that has a Document which has a DocumentData.
I want to be able to add different types and columns of data to DocumentData, so for example I can have DocumentData with 3 columns of type DateTime,Int32,Int32. And then have another table with 5 columns of types Datetime,double,Int32,Int32,Int32. Basically what I'm going for is to have something like this in my code:
using(var unit = new UnitOfWork(new SessionContext()))
{
var data = unit.Sessions.GetCurrent().Document.DocumentData;
var row = data.Column[0].Rows[5]... etc.
}
This is because DocumentData is generated from csv specified by a user, so each DocumentData is made of different columns.
EDIT:
I want to know how to create a table on runtime and assign whatever columns I want to it. So I want to be able to do something like:
var doc = new Document();
session.Document = doc;
doc.Columns.Add(new Column() {Rows = rows});
doc.Columns.Add(new Column() {Rows = rows2});
doc.SaveChanges();
and then have second table with different columns.
EDIT2:
To make it more clear I want to convert this:
public class DocumentData {
public List<DocumentColumn> Columns { get; set; }
}
public class DocumentColumn {
public string ColumnName { get; set; }
public List<object> Rows { get; set; }
}
into ado.net entities so I can save them to database.
You can use a SQL statement to create tables at runtime (via dbcontext). I don't think that its possible to bind such a table to an entity / class at runtime after the database / context is initialized.
But if you don't have to use the different / variable columns as query / selection parameters, simply serialize the document class in a single BLOB column and your done.
I have two entites with association. I create a dataGridView by drag and drop from objects Data Source and manually binding from to list. Everything works fine with one entity. Is there any possibility of create one dataGridView with two entities(Zamow and ZamSkany) by drag and drop + manually filling? I can do this by view (on SQL side) but in same cases I'd like to have other possibilities.
pg = new PGEntities();
BindingList<Zamow> myList;
var query = (from zam in pg.Zamow where zam.Rok == 2012 select zam).Take(100);
MyList = new BindingList<Zamow>(query.ToList());
zamowBindingSource.DataSource = MyList;
Yes, try to create Class, let say a ViewZamowAndSamSkany
public class ViewZamowAndSamSkany
{
public string Data { get; set; }
public string Proforma { get; set; }
//and Others Properties
}
and now, rebuild your project and from the Objects Data Source add the ViewZamowAndSamSkany then drag-drop to your Form as a DataGridView and you can apply the linq-entites inner join
var query = (from zam in pg.Zamow
join skany in zam.NUMBER equals skany.NUMBER
where zam.Rok == 2012
select new ViewZamowAndSamSkany
{
Data = zam.Data,
Proforma = zam.Proforma
}).Take(100);
MyList = new BindingList<ViewZamowAndSamSkany>(query.ToList());
zamowBindingSource.DataSource = MyList;
I´m having a problem, I retrieve all the Loans I have stored in my database like this:
list_loans = db.Loan.Where(x => x.State.id_state != 6).ToList();
db is the Object context.
Then, I assign that list as the DataSource for my DataGridView.
dgv_Loans.Datasource = list_loans;
With that info, I add some columns. Like for example, installments left to pay. I get that value by counting the result of a query.
The user can order the result using some options. Is easy to order the result from the fields that the entity have (using linq), but I dont know how to order the results using this new columns.
I read some posts here and tried this:
dgv_Loans.Sort(dgv_Loans.Columns["installments_left"], ListSortDirection.Ascending);
By doing this, I´m getting the following exception at runtime:
"DataGridView control must be bound to an IBindingList object to be sorted."
Is there anyway to use linq to orderby created columns in a DataGridViewColumn? Or how can I solve this error?
I know there are related posts, but after reading them, I can´t find a solution to this specific problem. Thats why I showed how I implemented to get some advice..
Rather than binding directly to the list retrieved from database, what I generally do is have a view class and have all the calculated properties in that class
public class LoanView : Loan {
public LoanView(Loan loan){
}
public int InsallmentsLeft { get { return ...; } }
}
and then bind the datasource to a list of this, this keeps sorting working.
Concerning about Sort datagridview by created columns using Entity Framework
I guess you need this Presenting the SortableBindingList<T>
Usage:
loanBindingSource.DataSource = new SortableBindingList<Loan>(list_loans.ToList());
dgv_Loans.Datasource = loanBindingSource;
int ID = Convert.ToInt32(cmbDepartments.SelectedValue);
var EmployeeList = from Employee in db.Employee
where Employee.DepartmentID == ID
select new
{
Employee.FirstName,
Employee.LastName
};
dataGridView1.DataSource = EmployeeList.ToList();
You could directly give the data source to dataGridView1.DataSource but you must write ToList() at the end of your query:
int ID = Convert.ToInt32(cmbDepartmanlar.SelectedValue);
dataGridView1.DataSource = (from Employee in db.Employee
where Employee.DepartmentID == ID
select new
{
Employee.FirstName,
Employee.LastName
}).ToList();
This is what i am trying to do. I have a database that i am reading from using the code:
OleDbCommand command;
command = new OleDbCommand("SELECT " + Student.ID + " FROM " + newStudent.DataFile, conn);
conn.Open();
dt.Load(command.ExecuteReader());
conn.Close();
I then have the datatable bind to a datagridview and display the contents of the table.Now the problem is, i have more information to add to the datatable dt that is not in the database. For example, i have a field for the student object called Grade that is not found in the datafile but entered in by the user and stored in a property for the student object.
Instead of loading the query result into a datatable, is there a way to load it into a list so i can manually create rows and columns for a datatable in another method and then add the contents of the list(containing id) and the grade information in the student object manually?
If you don't fancy going for a full blown ORM framework such as the one #Bas has suggested...
Take a look at the ToTable method available from on a Datatable's Dataview. You can get the DataView for your Datatable simply using DataTable.DefaultView:
List<Long> myList = dt.DefaultDataView.ToTable(True, "ID").AsEnumerable().ToList()
myList.Add(1234)
//etc
Alternatively, you can load the additional data you want to append into a second datatable, and use the DataTable.Merge Method
EDIT: To account for wanting to add additional columns, you can change the above list suggestion as follows:
// Create a class to hold the information you want to bind,
// you could use anonymous types if preferred
class MyDataRow
{
public long ID { get; set; }
public string AnotherColumn { get; set; }
public string AndAnotherColumn { get; set; }
}
// then later on when creating that list use something along the lines of:
List<MyDataRow> myList = dt.DefaultDataView.ToTable(True, "ID").AsEnumerable().Select(x => new MyDataRow { ID = x.ID }).ToList()
// you now have a list of MyDataRow which you can work with
// for example...
if (myList.Any())
myList.First().AnotherColumn = "foo";
// as an exmaple of using an anoymous type (not my preference, but an option nonetheless)
var anonymousList = dt.DefaultDataView.ToTable(True, "ID").AsEnumerable().Select(x => new { ID = x.ID, whateverYouWantToCallIt = "some other data but this is read only property" }).ToList()
// you can work with the anonymous list in much the same way, it just isn't explicitly declared
// and the properties are Read Only
if (anonymousList.Any())
Console.WriteLine(anonymousList.First().whateverYouWantToCallIt);
You could use Entity Framework to extract an object model from your database. Afterwards you could add the property for grade to your object (due to the fact that these objects are created in partial classes). This provides a (vastly) more structured / easy to use way of adding custom logic and attributes to your data structure.
You can bind your GUI components to entity framework objects in a similar way as you would using conventional ADO.NET.