Concept of a database driven program in VB.NET - database

I have been developing programs in VB.NET for a few years and am familiar with it. The area where I do not have a lot of exposure is databases.
I am writing a program (for my personal use) called movie manager. It will store information on movies I have. I have selected Sql Server Compact Edition database. Assume I have a database with two tables namely Info and Cast. Info table has a few columns such as movie_name, release_date and so on. Cast table has few cols such as first_name,last_name etc.
Right now I have created a DataSet which reads all the info of tables from database (opens connection, fills tables info, closes connection). This way in a global variable I have a snapshot of database.
My queries :
Once I have data with me, every time I need to add, edit or delete a record I have to open a connection, fire an sql and close the connection. Right ? Is there a way to do this without using Sql ? Plus is this concept okay.
Since I am not using structures so I need to create empty datasets to store temp information. Is this convenient ?
If I have to search for a specific thing in dataset table, then do I have to loop thru all items or can I use sql on dataset or is there an alternate ?

1)Once I have data with me, every time I need to add, edit or delete a record I have to open a connection, fire an sql and close the connection. Right ? Is there a way to do this without using Sql ? Plus is this concept okay.
No. To update a database, you have to use the database. Create a stored procedure in the database to handle your functionality and then call it from the code and pass in whatever data needs saved. DO NOT USE INLINE SQL. Paramterized stored procedures are the way to go.
2) Since I am not using structures so I need to create empty datasets to store temp information. Is this convenient ?
It depends on what you're doing. I would create an object model to retain my updated data and then I'd pass the properties into the stored procedure when it was time to save my changes.
3) If I have to search for a specific thing in dataset table, then do I have to loop thru all items or can I use sql on dataset or is there an alternate ?
You can loop the rows or you can use linq to pull what you need out. Linq is really nice as it's basically .NET coded queries against a collection.
There are plenty of tutorials/guides out there to show you how to update via stored proc call form your code. There are a ton of linq tutorials as well. Basically, a linq query against your table will look something like:
dim result as Generic.List(of String) =
(from r in table.AsEnumerable()
select r
where r["columnName"] = "the value").ToList()
This syntax is probably a bit off, but it looks something like that.
Edit
Your Model:
Public Class EmployeeModel
Public Property Id
Public Property FirstName
Public Property Last Name
Public Property JobCode
Public Sub EmployeeModel(your params)
//set properties
End Sub
End Class
Your DAL:
Public Shared Class EmployeeDAL
Public Shared Sub SaveEmployee(ByRef model as EmployeeModel)
// call your sp_SaveEmployee stored procedure and set the parameters to the model properties
// #id = EmpoyeeModel.Id
// #JobCode = Employee.JobCode
// ...
End Sub
End Class
I use VB every few months, so there are probably some small syntax errors in there. But that's basically all you need to do. The function to save your data is in the DAL, not in the class itself. If you don't want to use a DAL, you can put the save functionality in your class, though. It'll work the same way, it's just not as clearly separated.

On your Questions.
number 1: You have to connect to database in order to store and retrieve data. There are lots of ways on how to deal with it and one way of it is to use app.config or you may simply create a function that calls the connection every time you need it.
number 2: Since you are dealing with dataset here are some tips you might want to look at DataSet
number 3: You can also try using Data Adapter and Data Table. I am not sure what you meant by your question number 3.
Cheers

I have problem with the way you are using your database and the ram of your computer.
Problem1: since you already have a database for holding the movies information why are you again holding the same information in memory?, creating an extra overhead. if your answer is for performance or i have cheap memory then why don't you use xml or flatfile instead? Database is not needed with this senario.
Problem2: You are like a soldier who dosent know about the weapon he use? right? because you are asking silly questions your first question about opening connection.. the answer is yes you have to open the connection every time save/read the data and close it as soon as possible.
your second question about convinent the answer is no. instead create class with all field as property and some method for initialization,saving,deleting. this way you have to write less code. nad suppose you have a movie names xyz there can be another movie xyz how will you distinguish it? if you have whole information b4 you you can do it via release date ,casts etc, but still it will be hard, so create a primary key for both your table
and finally your 3rd question , it will be easier to use use sql queries than looping thru the dataset(get rid of the dataset as soon as possible)
wish yu good luck on the road to rdbms

Related

ODBC and data binding by [Table].[column]

I'm rewriting an older-than-dirt MFC application, ripping out the old MFC-based DB code and re-working queries to make it run faster. This code works with a MS Access 2003 .mdb file.
The old code used the convenience functions like RFX_Bool, RFX_Long, RFX_Int to read from the records. These are nice, and I am reading about binding in ODBC using SQLBindCol to set the bindings ahead of time to avoid that extra processing time for each row. This is great, but I see SQLBindCol only takes the column number, not the name. What if I want to bind using the column name like with the RFX_* functions? SQLDescribeCol gives the column names, but it doesn't have the "full" name, i.e. [Table/Alias].[Column]. Some of my queries involve JOIN'ing the same table multiple times with aliases, so I can't bind the column by the column name alone. If I plug my query into Access, the Datasheet view shows the alias in the column name. I'm currently using my connection string with Driver={Microsoft Access Driver (*.mdb, *.accdb)}, if it matters.
tl;dr How do I do MFC's RFX_*(fieldExchange, L"[Table].[Column]", &variable) in the modern ODBC API?
OK, I think I understand what the RFX functions are doing now, and I think I know what I need to do.
The MFC ODBC classes construct your query programmatically, so after starting with SELECT, UPDATE, etc, every call to RFX_* simply appends the field name to the query, then ties a reference to your variable to the column index, which it increments after every call. So I just need to append my fields to my queries with a helper function the same way MFC does, in order to bind my pointers in the same way MFC does.
Hopefully this is helpful to somebody.

Multimapping in Dapper Without Custom SQL

Is there a way to use multimapping in Dapper in a generic way, without using custom SQL embedded in C# code?
See for example
Correct use of Multimapping in Dapper
Is there a generic way to query the data from 2 related entities, where common fields are determined automatically for join?
Don't do this. Don't even think this way! Databases are long lasting and normalized. Objects are perishable and frequently denormalized, and transitioning between the two is something to do thoughtfully, when you're writing your SQL. This is really not a step to automate. Long, painful experience has convinced many of us that database abstractions (tables and joins) should not just be sucked into (or generated out of) code. If you're not yet convinced, then use an established ORM.
If, on the other hand, you absolutely want to be in control of your SQL, but its the "embedding" in string literals in C# that bugs you, then I couldn't agree more. Can I suggest QueryFirst, a visual studio extension that generates the C# wrapper for your queries. Your SQL stays in a real SQL file, syntax validated, DB references checked, and at each save, QueryFirst generates a wrapper class with Execute() methods, and a POCO for the results.
By multi-mapping, I presume you want to fill a graph of nested objects. A nice way to do this is to use one QueryFirst .sql per class in your graph, then in the partial class of the parent, add a List of children. (QueryFirst generated POCOs are split across 2 partial classes, you control one of them, the tool generates the other.)
So, for a graph of Customers and their orders...
In the parent sql
select * from customers where name like #custName
The child sql
select * from orders where customerId = #customerId
In the parent partial class, for eager loading...
public List<Orders> orders;
public void OnLoad()
{
orders = new getOrders().Execute(customerId); // property of the parent POCO
}
or for lazy loading...
private List<Orders> _orders;
public List<Orders> orders
{
get
{
return _orders ?? _orders = new GetOrders().Execute(customerId);
}
}
5 lines of code, not counting brackets, and you have a nested graph, lazy loaded or eager loaded as you prefer, the interface discoverable in code (intellisense for the input parameter and result). Their might be hundreds of columns in those tables, whose names you will never need to re-type, and whose datatypes are going to flow transparently into your C#.
Clean separation of responsibilities. Total control. Disclaimer : I wrote QueryFirst :-)
Multimapping with Dapper is a method of running multiple SQL queries at once and then return each result mapped to a specific object.
In the context of this question, Multimapping is not even relevant, re: you're asking for a way to automatically generate a SQL query from the given objects and creating the correct joins which would result in a single SQL query which is not related to Multimapping.
I suspect what you're looking for is something along the lines of the Entity Framework. There are a couple of Dapper extension projects you may want to look into which will generate some of your SQL. See: Dapper.Rainbow VS Dapper.Contrib

ADO - Can I edit results of a complex query with multiple join statements?

I'm working on a data conversion utility which can push data from one master database out to a number of different databases. The utility its self will have no knowledge of how data is kept in the destination (table structure), but I would like to provide writing a SQL statement to return data from the destination using a complex SQL query with multiple join statements. As long as the data is in a standardized format that the utility can recognize (field names) in an ADO query.
What I would like to do is then modify the live data in this ADO Query. However, since there are multiple join statements, I'm not sure if it's possible to do this. I know at least with BDE (I've never used BDE), it was very strict and you had to return all fields (*) and such. ADO I know is more flexible, but I don't know quite how flexible in this case.
Is it supposed to be possible to modify data in a TADOQuery in this manner, when the results include fields from different tables? And even if so, suppose I want to append a new record to the end (TADOQuery.Append). Would it append to two different tables?
The actual primary table I'm selecting from has a complimentary table which is joined by the same primary key field, one is a "Small" table (brief info) and the other is a "Detail" table (more info for each record in Small table). So, a typical statement would include something like this:
select ts.record_uid, ts.SomeField, td.SomeOtherField from table_small ts
join table_detail td on td.record_uid = ts.record_uid
There are also a number of other joins to records in other tables, but I'm not worried about appending to those ones. I'm only worried about appending to the "Small" and "Detail" tables - at the same time.
Is such a thing possible in an ADO Query? I'm willing to tweak and modify the SQL statement in any way necessary to make this possible. I have a bad feeling though that it's not possible.
Compatibility:
SQL Server 2000 through 2008 R2
Delphi XE2
Editing these Fields which have no influence on the joins is usually no problem.
Appending is ... you can limit the Append to one of the Tables by
procedure TForm.ADSBeforePost(DataSet: TDataSet);
begin
inherited;
TCustomADODataSet(DataSet).Properties['Unique Table'].Value := 'table_small';
end;
but without an Requery you won't get much further.
The better way will be setting Values by Procedure e.g. in BeforePost, Requery and Abort.
If your View would be persistent you would be able to use INSTEAD OF Triggers
Jerry,
I encountered the same problem on FireBird, and from experience I can tell you that it can be made(up to a small complexity) by using CachedUpdates . A very good resource is this one - http://podgoretsky.com/ftp/Docs/Delphi/D5/dg/11_cache.html. This article has the answers to all your questions.
I have abandoned the original idea of live ADO query updates, as it has become more complex than I can wrap my head around. The scope of the data push project has changed, and therefore this is no longer an issue for me, however still an interesting subject to know.
The new structure of the application consists of attaching multiple "Field Links" on various fields from the original set of data. Each of these links references the original field name and a SQL Statement which is to be executed when that field is being imported. Multiple field links can be on one single field, therefore can execute multiple statements, placing the value in various tables, etc. The end goal was an app which I can easily and repeatedly export a common dataset from an original source to any outside source with different data structures, without having to recompile the app.
However the concept of cached updates was not appealing to me, simply for the fact pointed out in the link in RBA's answer that data can be changed in the database in the mean-time. So I will instead integrate my own method of customizable data pushes.

How do I read data from a database using LINQ to SQL in VB using an IQueryable?

I am fairly new to visual basic and know only a little about LINQ and SQL. I know how to select items from an array with LINQ, but what I can't figure out how to do is access a database using an IQueryable. I connected the database to my project, added two classes from the database to the "LINQ to SQL" .dbml file and saved it. In my programming assignment, I am not supposed to create a data source (table thing) to display the data, but update my own interface manually. In order to do it, I was told to instantiate this:
Private dogs As System.Linq.IQueryable(Of Dog)
(Dog is a class that I added to my .dbml file from the database file)
Also, I am told it involves using a method
.AsEnumerable.ElementAt(index As Integer)
And somehow I am supposed to load database data from/using this. Help please if you can. I got screwed over by my professors as our online assignment program was down the whole thanksgiving break so I'm here doing this at the last minute. Thanks.
You have to make an instance of your data context class (which has the same name as your dbml + "DataContext"). Let's say it is AnimalsDataContext:
using (var context = new AnimalsDataContext())
{
var dogs = context.Dogs;
....
}

Is there any overhead with LINQ or the Entity Framework when getting large columns as part of an entity?

Let's say you have a table containing articles and you want want to display a list of them, excluding the actual article text. When you get a list of the article objects using LINQ or the Entity Framework, is there a LOT of overhead associated with getting that text column too? I assume that when you start enumerating the list, the article text will be stored in memory until the objects are disposed of.
So would it make sense to create an intermediary object that doesn't contain the text column? If so, how would you do this? Make a class inside your DAL, allow the ORM to automatically create one by setting up a stored procedure, or some other process?
The overhead isn't huge (just the cost of sending the data over the wire), but if you don't need the data sure, don't return it. I find the easiest way is to use anonymous types:
from a in Context.Articles
select new {Name = a.Name, Author = a.Author};
Since you're not actually materializing any Article instances, the Entity Framework won't need to fill out all the properties of an instance.
If you don't need the data you should definitely create a different type. By convention I typically name this sort of class "nnnInfo" or "nnnListItem". To create ArticleListItem, in L2S, simply drag the table to your DataContext designer a second time. Then rename it from 'Article1' to 'ArticleListItem' and remove the unneeded properties (rt click, delete). In EF, the process would be similar. As Craig notes, you could use anonymous types, but by creating a concrete type, you can reuse throughout your app, expose via services, etc.
A second way to do this would be to create the class manually and write an extension method to return ArticleListItem:
public static IQueryable<ArticleListItem> ToListItems(this IQueryable<Article> articles)
{
return from a in articles select new ArticleListItem{ Title = a.Title, ...}
}
This would allow you to "cast" any queries against Article as ArticleListItem...

Resources