📄 metakit quick and easy storage for your tcl application.mht
字号:
notation like for views and rows, but accessed through MetaKit commands =
like=20
mk::get and mk::set. </P>
<H2>Managing Data Files</H2>
<P>The example earlier actually showed you all you normally need to =
worry about=20
data files. </P>
<P>Pick a file on disk to store your data. Use the "<CODE>mk::file open =
<I>tag=20
filename</I></CODE>" command to open the file and associate a tag with =
that=20
file, e.g. "<CODE>mk::file open db mydata.db</CODE>" to create or open =
the=20
mydata.db file and associate the tag "db" with the file. </P>
<P>As you make changes, you should periodically call "<CODE>mk::file =
commit=20
<I>tag</I></CODE>" to flush your changes to disk. </P>
<P>When you're done with the datafile, simply call "<CODE>mk::file close =
<I>tag</I></CODE>". </P>
<P>That's all there is to that. </P>
<H2>Structuring What You Store</H2>
<P>After opening your data files, the first thing you'll need to do is =
specify=20
what kind of data is stored in them. Remember that your data files are=20
structured as one or more <I>views</I>, where each view acts like a big =
array to=20
hold your data in a set of rows. Because each row in a single view must =
have the=20
same set of properties - the same structure - you'll have to define a =
view for=20
each type of data you want to store in your data file. </P>
<P>Different types of data will require different properties. For =
example, an=20
"employee" in a Human Resources application will hopefully have =
different=20
properties (e.g. name, salary, etc.) than a "city" in a geographic =
application=20
(e.g. latitude, longitude, name, population). Even if two data types did =
have=20
the same structure (e.g. "name" and "id" might apply to a lot of things) =
you=20
still wouldn't want to confuse them, so you would still want to create =
two=20
separate views. </P>
<P>To specify a view for a certain type of data, first identify all the=20
properties that you would want to store for objects of that type. Make =
sure to=20
break things up into as small pieces as make sense for your application, =
rather=20
than combining several items into a single property. For example, many=20
applications would be better served by multiple properties like "street=20
address", "city", "state" and "zip code" rather than a single "address" =
which=20
combines all four individual pieces. Combining them into one would for =
example=20
make it harder to search for all entries from a particular country. </P>
<P>Once you've listed out all the properties, you have to give each a =
name that=20
you'll use to refer to the property in your program. This will be like a =
variable in your program; so use things like "employeeid" rather than =
"Employee=20
Identification Number". As with naming any variables, try to be specific =
and=20
unambiguous. If you have several different types of data each referred =
to by a=20
different unique identifier, use the more explicit "employeeid" and =
"partid"=20
rather than a simple "id". </P>
<H3>Defining the View</H3>
<P>To actually create the view and give it its structure, use the=20
"<CODE>mk::view layout</CODE>" command. This takes a view name (a data =
file tag=20
plus the name you'd like to assign to this view) and a list of =
properties as=20
arguments. For example: </P><PRE>mk::view layout db.employees "name =
employeeid salary"
mk::view layout db.cities "cityname latitude longitude country =
population"</PRE>
<P>You have to issue this command to create the view after first =
creating the=20
data file (via "<CODE>mk::file open</CODE>") and before storing any data =
in it.=20
You should also issue this command after opening your existing data file =
(again,=20
via "<CODE>mk::file open</CODE>"). Since in MetaKit there's no explicit=20
difference between creating a new file and opening an old one, it's best =
to=20
always specify the view immediately after opening the file. </P>
<H2>Storing and Retrieving Data</H2>
<P>Now that we've defined what we're going to store in a view, it's time =
to see=20
how to actually store something there. In this section, we'll assume =
we're=20
dealing with employee records, using a view set up as follows: =
</P><PRE>mk::file open db mydata.db
mk::view layout db.employees "name employeeid salary"</PRE>
<H3>Adding Rows</H3>
<P>Remember that each view holds an array of rows, indexed by position =
(zero=20
being the first, one being the second, etc.). Initially, a view will =
have no=20
rows stored in it. The obvious thing then to do is add a new record, =
which can=20
be done via the "mk::row append" command, as follows: </P><PRE>set row =
[mk::row append db.employees]</PRE>
<P>This will add a new row at the end of any existing rows. Initially, =
all the=20
properties for this row will be set to empty strings. The command will =
return a=20
string that you can use to refer to the individual row. For the first =
row=20
created, this will be "<CODE>db.employees!0</CODE>", for the second=20
"<CODE>db.employees!1</CODE>", and so on. You can also set one or more=20
properties for the new row by passing the name and values of the =
properties to=20
the "<CODE>mk::row append</CODE>" command: </P><PRE>mk::row append =
db.employees name "Mark" employeeid 1 salary 10
mk::file commit db</PRE>
<P>The command "<CODE>mk::view size <I>viewname</I></CODE>" command will =
tell=20
you how many rows are in the specified view. </P>
<H3>Setting Properties</H3>
<P>To set one or more properties for a row, use the "mk::set" command, =
which=20
takes a row reference (i.e. <CODE>db.viewname!rownum</CODE>) and a list =
of one=20
or more property names and values. So for example to change the salary =
of the=20
employee at index 3 in the employees view, we could use: =
</P><PRE>mk::set db.employees!3 salary 25</PRE>
<P>The last <CODE>mk::row append</CODE> in the previous section could =
also be=20
written as: </P><PRE>set row [mk::row append db.employees]
mk::set $row name "Mark" employeeid 1 salary 10</PRE>
<P>Remember to use "<CODE>mk::file commit</CODE>" periodically after =
storing=20
data in your files. </P>
<H3>Retrieving Properties</H3>
<P>The <CODE>mk::get</CODE> command is used to retrieve the values of =
one or=20
more properties for a row. There are two forms. In the first, you =
provide a list=20
of properties you'd like to retrieve, and the command returns a list of =
the=20
values of those properties. For example: </P><PRE>puts [mk::get =
db.employees!0 name employeeid]
=3D> Mark 1</PRE>
<P>In the second form, when mk::get is called without a list of property =
names,=20
the command will return a list of all properties and their values: =
</P><PRE>puts [mk::get db.employees!0]
=3D> name Mark employeeid 1 salary 10</PRE>
<H3>Iterating over Rows</H3>
<P>If you just want to iterate over all the rows in a view, for example =
to do=20
simple reporting or batch modifications, you can do this with the=20
"<CODE>mk::loop</CODE>" command. Like "for" loop constructs in =
programming=20
languages, a loop variable will be set to point to each row in turn. For =
example, to print out the names of all employees in our example: =
</P><PRE>mk::loop i db.employees {
puts [mk::get $i name]
}</PRE>
<H3>Deleting Rows</H3>
<P>You can delete one or more rows using the "mk::row delete" command. =
For=20
example: </P><PRE>mk::row delete db.employees!2 # delete a single row
mk::row delete db.employees!5 3 # delete three rows starting at index =
5</PRE>
<P>In general, you can't use "mk::row delete" within a "mk::loop" =
construct.=20
Because "mk::loop" uses the index (row number) to keep track of the =
current=20
item, and "mk::row delete" removes rows, the loop counter will get =
thrown off.=20
</P>
<H2>Queries</H2>
<P>If you're searching for only particular data items, its possible to =
do it=20
simply by iterating over each row and comparing the row's properties to =
what=20
you're looking for. However, its easier and more efficient to use the=20
"<CODE>mk::select</CODE>" command, which will do the work of searching =
through=20
the rows for you. </P>
<P>The <CODE>mk::select</CODE> command will search through the rows in a =
view=20
and return a list of row numbers matching a given search criterion. So =
to search=20
for all employees with a salary of 10, we could do the search, and =
iterate over=20
these rows to print their names: </P><PRE>set rownums [mk::select =
db.employees salary 10]
foreach i $rownums {
puts [mk::get db.employees!$i name]
}</PRE>
<P>The search criterion is specified as a property followed by its =
value. To=20
search for rows matching multiple criterion you can specify multiple=20
property/value pairs (e.g. "salary 10 name Mark"), where all of the =
properties=20
must match. The default matching is case-insensitive. </P>
<H3>Other Options</H3>
<P>You can also specify other search options, beyond just a simple check =
if a=20
property equals a given value ("<CODE>property value</CODE>"). These =
include:=20
</P>
<TABLE cellPadding=3D5>
<TBODY>
<TR>
<TD>-min <I>property value</I> </TD>
<TD>Property must be greater than or equal to value. </TD></TR>
<TR>
<TD>-max <I>property value</I> </TD>
<TD>Property must be less than or equal to value. </TD></TR>
<TR>
<TD>-exact <I>property value</I> </TD>
<TD>Exact case-sensitive string match. </TD></TR>
<TR>
<TD>-glob <I>property value</I> </TD>
<TD>Glob-style (i.e. string match) matching. </TD></TR>
<TR>
<TD>-globnc <I>property value</I> </TD>
<TD>Case-insensitive glob-style matching. </TD></TR>
<TR>
<TD>-regexp <I>property value</I> </TD>
<TD>Match by regular expression. </TD></TR>
<TR>
<TD>-keyword <I>property value</I> </TD>
<TD>Match if value is included as a word or prefix of a word in the=20
property. </TD></TR></TBODY></TABLE>
<P>You can also sort the results according to the value of a property=20
("<CODE>-sort <I>property</I></CODE>" or reverse ordered sort with =
"<CODE>-rsort=20
<I>property</I></CODE>"). There are also other options allowing you to =
choose=20
the maximum number of results to return, at what index to start the =
search, and=20
so on. See the reference manual for details. </P>
<H2>Common Idioms</H2>
<P>So far we've covered all the MetaKit commands you'll normally need =
for your=20
application, including working with data files, specifying views, =
adding,=20
modifying and deleting rows, and searching for particular rows. </P>
<P>In this section, we'll describe some common programming idioms that =
you'll=20
find yourself using with your MetaKit applications. These are just some =
simple=20
techniques that you'll find make building your programs easier. </P>
<H3>Multiple Views</H3>
<P>This one is simple; remember that if you're storing different types =
of data,=20
you should place them in different views. Using multiple "<CODE>mk::view =
layout</CODE>" statements, you can effectively partition a single data =
file into=20
multiple different areas. Don't try to take shortcuts by playing tricks =
like "if=20
this property is set to this value, its really this type of data, so =
this other=20
field means..." You'll only get burned later. Set up a separate view. =
</P>
<H2>Generating Unique Ids</H2>
<P>In MetaKit, you've seen that individual rows are referred to by their =
row=20
number (i.e. their position or index within the entire view). Because =
this can=20
change (when rows are inserted or deleted), it's often valuable to =
assign a=20
unique identifier to the object, to refer to it over a longer-term =
basis. For=20
example, employees may be assigned a unique employee id, etc. (such ids =
are=20
often referred to as the "primary key"). </P>
<P>One approach to generating these unique ids in MetaKit is to use a =
separate=20
"control" view within the data file. This view would hold a single row,=20
containing a counter used to generate this id. For example: =
</P><PRE>mk::file open db mydata.db
# create a control view holding our counter
mk::view layout db.control {
nextid:I
}
# initialize it if needed
if {[mk::view size db.control]=3D=3D0} {
mk::row append db.control nextid 1
}
# procedure to return a unique identifier
proc getuniqueid {} {
set id [mk::get db.control!0 nextid]
mk::set db.control!0 nextid [expr $id+1]
mk::file commit db
return $id
}</PRE>
<H3>Reading/Writing from Tcl Arrays</H3>
<P>The "<CODE>mk::get</CODE>" command returns a Tcl list in the format =
of=20
"<I><CODE>property value property value...</CODE></I>". We can take =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -