|
Employees can have the same name though. I do see what you saying, but problem lies more on the way I build my classes. Having most of the list static so I can access them from anywhere. I don't think this is right though. Well it is right but proberly doesn't follow best practises.
|
|
|
|
|
Bardy85 wrote: Well it is right but proberly doesn't follow best practises.
A "best practice" often turns into a golden hammer. There's a lot of ways to load data, some make sense in a webapp, others make more sense in a console-application. Using NHibernate from a console-app just to update the name of a single employee would be overkill.
Most answers here will be variations on the ActiveRecord-pattern to store a single record. It would also make sense to store multiple records in some kind of collection[^].
I are Troll
|
|
|
|
|
I would do this:
public class Employee
{
}
public class EmployeeList : List<Employee>
{
public EmployeeList(bool populateNow)
{
if (populateNow)
{
GetFromDatabase();
}
}
public void GetFromDatabase()
{
this.AddRange(blah blah);
}
}
EmployeeList employees = new EmployeeList(true);
The list should know how to load itself, and can take care of all the nasty stuff behind the scenes and abstracted out of the UI code.
.45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
Thanks, nice way of doing it.
If you wanted to initialize the list once at start of your application and then be able to call it through out the scope of you app, how would you do it?
|
|
|
|
|
Put it in a static class and intitialize it in the constructor of the that class.
public static class Globals
{
public static EmployeeList Employees { get; private set; }
static Globals()
{
Employees = new EmployeeList(true);
}
}
.45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
If you want to cache your Employees for use throughout your application and it's acceptable to not reload them (i.e. they will not be changed by someone else acessing the DB) then it's OK to keep a static reference.
One or two points though. Don't make fields public, you should create a static readonly property (i.e. only a getter) to expose the cached List.
If you have a lot of data stored in your list then you may end up with memory issues, so it may be wise to only store the basic information such as ID and Name, and look up the rest of the data when required.
Have you considered using the Singleton pattern and have a Manager/Factory class that creates the list only when it is first needed? It won't offer any huge improvements, but can be a more logical approach. Without knowing the exact requirements and other implementation details it's hard to say but may be worth investigating.
Dave
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Thanks,
I do have quite a few records, anywhere up to 10000. I do quite a few checks on the List though, every day I get a bulk file of employees and check if the employee exists, if he does I need to check if any of his details have changed. (Every single field)
I think one select of all the data and then data lookups would be faster then 10000 selects?
|
|
|
|
|
10000 doesn't sound like a lot, it depends on how much space each element takes. If it's only say 100 bytes then that's approx 1MB of memory. If however you have names, addresses, photo etc... each record could be much larger. If it were a meg each then that would be 10GB and unless you have a mega system you would come crashing to a halt.
Even if useage is low, the volume of Employees may change, and the storage requirements may expand later (scans of signed contracts of employemt as an example) so I would build for that now and just cache the data that is required to make the application useable, and do a DB lookup for the non cached data when needed.
Dave
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
|
Hi,
1.
if it is a list, then make it inherit from List, as John said.
2.
static seldom is good; what happens if you suddenly need two lists of employees, e.g. because your program suddenly has to deal with two companies?
the best use for static is for holding overall counters and other statistical information on your class, information that transcends all the class instances.
modified on Sunday, January 17, 2010 5:07 PM
|
|
|
|
|
Thanks,
I've just started implementing the : List<t>.
Don't know why I didn't think about it before.
Thanks again for the help.
|
|
|
|
|
You're welcome.
|
|
|
|
|
Hi all, i counter this statment at some code, but i don't undestand what means, so, i need helping of what it means in detail...
[StructLayout(LayoutKind.Sequential)]
Thanks......
|
|
|
|
|
Maybe this[^] helps. If not, ask more specific questions, with context and purpose.
|
|
|
|
|
Normally the compiler pads structures out so that it can use optimised four-byte transfer operations. But different compilers do that in different ways. LayoutKind.Sequential lays the structure out exactly as you specify, not how the compiler thinks will run well.
It's commonly used in PInvoke, because C# and C compilers are likely to pad things out differently.
|
|
|
|
|
Believe it or not, MSDN is your friend. Search it.
50-50-90 rule: Anytime I have a 50-50 chance of getting something right, there's a 90% probability I'll get it wrong...!!
|
|
|
|
|
If you don't specify it, the compiler would be free to sort the fields by size so as to minimize padding.
|
|
|
|
|
It's commonly used when using external C/C++ dlls (PInvoke).
When a structure is being passed as a parameter to an external function then the called C/C++ function needs to know exactly where to find the relavent parts of the structure in memory. It does this using byte offsets from the start address (pointer) of the struct.
Imagine you had this structure
public struct MyStruct
{
public byte a;
public int b;
} Without specifying the LayoutKind , this could end up being layed out in memory with b first. This would be catastrophic for the external function as it would assume the fields to be layed out in sequence - so with a first. As a result the data retrieved from memory would be incorrect. To make sure that the sequence of fields is preserved, we use LayoutKind.Sequential .
Another common one is LayoutKind.Explicit (most commonly when used with C/C++ unions). Here you explicitly state the offset for each field using the FieldOffset attribute.
Dave
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hello, I'm building a database WinForm application.
The data objects in my first application where based up on SQLDataConnector, DataSet, DataTables and SQLDataAdapter.
Now I moved on and I write Data object classes, which I fill with a SqlDataReader. Modifying the record is done by straight INSERT, UPDATE and DELETE queries written in a Data Object DB Class.
The technique is out of the book => Murach's ADO.Net 3.5 LinQ and the Entity Framework. After studying different technique I decided not to go for Entity Framework but hang around with writing my own data classes, making use of binding with data objects and most important ... understanding what happens under the Engine Cowling.
So far so GOOD.
The client interface works fine, but I like to give the User feedback as soon she/he is changing the content in one of the bounded controls (Textbox, comboBox, ect). In such case I like to show a pencil Icon on the form indicating the content has been changed. So I like to capture an event as soon the record becomes "DIRTY".
This way I can decided if an Update is required when the user clicks the button "Save and Close" (just like with leaving a MS Outlook contact form). If the 'IsDirty' property is 'false' the form just should close. Else it should write the changes back to the SQL server in advance of closing.
I studied the BindingSource control, but I cannot find an 'IsDirty' property as well no event related to this.
I found some articles on the web indicating the same problem. But the code samples are not providing a solution for me.
CONCREET: I like to customize the BindingSource by simply adding an "IsDirty" property and an "IsDirtychanged" event. Will this be an easy one????
Your help is most appreciated!
With kind regards,
Arjen Groeneveld
|
|
|
|
|
ArjenGroeneveld wrote: I studied the BindingSource control, but I cannot find an 'IsDirty' property as well no event related to this.
The BindingSource has a CurrentItemChanged -event[^] that might be of help.
ArjenGroeneveld wrote: CONCREET: I like to customize the BindingSource by simply adding an "IsDirty" property and an "IsDirtychanged" event. Will this be an easy one????
Meh, that's an unfair question! It would include subclassing the BindingSource , adding a field, an event, and the wiring for it. You'd also need a testproject, time and documentation - and you can ask additional questions here
I are Troll
|
|
|
|
|
Okay, Can you help me with the code?
Kind regards Arjen
|
|
|
|
|
ArjenGroeneveld wrote: Okay, Can you help me with the code?
If you want to save the Dirty-field along with the binding, then I'd suggest overriding the Binding class, and not the BindingSource . This might give you a start for a test-form, and having a property in a derived class, using databinding;
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
namespace Example
{
public class MyBinding : Binding
{
bool _isDirty;
public bool IsDirty
{
get
{
return _isDirty;
}
set
{
if (_isDirty != value)
_isDirty = value;
}
}
public MyBinding(string propertyName, object DataSource, string dataMember)
:base(propertyName, DataSource, dataMember)
{
}
}
public class Form1 : System.Windows.Forms.Form
{
static void Main()
{
Application.Run(new Form1());
}
private TextBox textBox1;
private ListBox listBox1;
private MyBinding myBinding;
public Form1()
{
InitializeComponent();
}
private void InitializeComponent()
{
SuspendLayout();
listBox1 = new ListBox();
textBox1 = new TextBox();
textBox1.Location = new Point(16, 68);
textBox1.Size = new Size(144, 20);
listBox1.Location = new Point(16, 8);
listBox1.Size = new Size(144, 50);
ClientSize = new Size(176, 100);
Controls.Add(textBox1);
Controls.Add(listBox1);
Name = "Form1";
Text = "Form1";
Load += new EventHandler(Form1_Load);
ResumeLayout(false);
}
private void Form1_Load(object sender, System.EventArgs e)
{
DataTable dt = new DataTable("employee");
dt.Columns.Add("firstname");
dt.Columns.Add("lastname");
dt.Rows.Add("john", "doe");
dt.Rows.Add("johnny", "walker");
listBox1.DataSource = dt;
listBox1.DisplayMember = "firstname";
myBinding = new MyBinding("Text", listBox1.DataSource, "lastname");
textBox1.DataBindings.Add(myBinding);
}
}
} Enjoy
I are Troll
|
|
|
|
|
Hello,
The end result I have in mind is an extended BindingSouce control, which is having an "IsDirty" property and an "IsDirtyChange" event.
The "IsDirtyChange" should only trigger when the User is making a change in one of the bounded controls.
I did some searching in FrameWork and I put the following together, but this code does not trigger when a user changes the content in a control. So something is missing.
Extended BindingSource coding...
namespace ACMAD.Business
{
class exBindingSource : BindingSource
{
// Internal variable
private bool flgIsDirty = false;
// Event
public event EventHandler IsDirtyChanged;
protected virtual void OnDirtyChanged(EventArgs e)
{
if (IsDirtyChanged != null)
{
IsDirtyChanged(this, e);
}
}
public bool IsDirty
{
get
{
return flgIsDirty;
}
set
{
flgIsDirty = value;
}
}
protected override void OnBindingComplete(BindingCompleteEventArgs e)
{
base.OnBindingComplete(e);
if (e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate)
{
if (!flgIsDirty && (e.BindingCompleteState == BindingCompleteState.Success) && e.Binding.Control.Focused)
{
flgIsDirty = true;
OnDirtyChanged(EventArgs.Empty);
}
}
}
protected override void OnCurrentChanged(EventArgs e)
{
base.OnCurrentChanged(e);
if (flgIsDirty == true)
flgIsDirty = false;
}
}
}
Form coding
I placed the exBindingSource on the form and connected an textbox to it.
One record is loaded with:
// Test purpose
exBindingSource1.Clear();
exBindingSource1.Add(ac_Model);
And I added an event
private void exBindingSource1_IsDirtyChanged(object sender, EventArgs e)
{
textBox1.Text = exBindingSource1.IsDirty.ToString();
}
The idea is that when the user makes a change to Textbox1 that Textbox2 is filled with the exBindingSource1.IsDirty value.
But ... nothing happens..
Your help is most appreciated.
With kind regards,
Arjen Groeneveld
|
|
|
|
|
I've added a theoretical OnCurrentItemChanged , but my DataGridView won't let me edit the collection. I can't test the code until tomorrow
protected override void OnCurrentItemChanged (System.EventArgs e)
{
base.OnCurrentItemChanged (e);
if (IsDirty == false)
IsDirty = true;
}
I are Troll
|
|
|
|
|
Hi, just want to ask if you solve your question, because right now I'm having problem same as yours, I would be thankful if you can share it, thanks.
By the way, what type of your datasource you used in extended bindingDataSource?
thank you..
|
|
|
|
|