Capítulo 4: Almacenamiento
introducción
capítulo 1: El modelo de aplicación "Longhorn"
capítulo 2: Creación de una aplicación "Longhorn"
capítulo 3: Controles y XAML
Capítulo 4: Almacenamiento
Brent Rector
Wise Owl Consulting
Enero de 2004
UPDATE: a pesar de lo que se puede indicar en este contenido, "WinFS" no es una característica que viene con el sistema operativo Longhorn. Sin embargo, "WinFS" estará disponible en la plataforma Windows en alguna fecha futura, por lo que este artículo sigue proporcionándose para su información.
Contenido
¿Qué es WinFS?
Modelo de programación de WinFS
Uso de la API de WinFS y SQL
Resumen
De alguna manera, equipo personal es un nombre inadecuado. La mayoría de las personas no usan un equipo personal para calcular. Usan un equipo para comunicarse (a través de correo electrónico o mensajería instantánea) y almacenar y organizar sus datos personales (como correo electrónico, documentos, imágenes y música digital). Desafortunadamente, mientras que el equipo actualmente almacena estos datos bastante bien, hace un trabajo relativamente deficiente de permitirle organizar la información para que pueda encontrarlo más adelante.
La capacidad de disco ha crecido aproximadamente un 70 % anualmente durante la última década. Actualmente es posible comprar unidades con más de 250 gigabytes (GB) de almacenamiento. Es probable que las unidades de 500 GB estén disponibles en los próximos años y que muchos sistemas tendrán más de una unidad de disco. Acabo de hacer una comprobación rápida en el equipo en el que estoy escribiendo este capítulo, y tengo 283.667 archivos en 114.129 carpetas en solo 200 GB de espacio en disco. Cuando olvidé exactamente dónde puse un archivo, puede tardar bastante tiempo en encontrarlo de nuevo. En el peor de los casos, tengo que buscar todo el contenido de cada disco. En unos años, las personas podrán almacenar millones de archivos, la mayoría de los cuales, si nada mejora, nunca volverán a ver.
Una razón por la que las personas tienen dificultades para encontrar información en su equipo se debe a la capacidad limitada para que el usuario organice los datos. La compatibilidad del sistema de archivos actual con carpetas y archivos funcionó bien originalmente porque era un paradigma familiar para la mayoría de las personas y el número de archivos era relativamente pequeño. Sin embargo, no le permite almacenar fácilmente una imagen de su compañero de trabajo Bob jugando softball en el picnic de la compañía 2007 en un parque local y luego encontrar la imagen al buscar documentos que:
- Mencione a Bob
- Implicación de deportes
- Relación con eventos de la empresa
- Pertenece al parque o a su zona circundante
- Se crearon en 2007
La estructura jerárquica de carpetas no funciona bien cuando desea clasificar datos de muchas maneras. Por lo tanto, tenemos un problema hoy en día en que tenemos muchas cosas para almacenar y ninguna buena manera de clasificarlo. Además de clasificar la información, que muchas personas asocian con la asociación de un conjunto fijo de palabras clave a los datos, las personas deben relacionar los datos. Por ejemplo, podría querer relacionar una imagen con el picnic de la compañía, o quizás quisiera relacionar una foto con Bob, que también es miembro de una organización a la que dono tiempo y esfuerzo, como contacto.
Otro problema es que almacenamos las mismas cosas en varios lugares en varios formatos. Los desarrolladores dedican mucho tiempo y esfuerzo a crear sus propias abstracciones de almacenamiento únicas para información diaria como Personas, Lugares, Tiempos y Eventos. Por ejemplo, Microsoft Outlook tiene una definición de un contacto. La libreta de direcciones de Microsoft Windows también tiene su propia definición de un contacto. Cada aplicación de mensajería instantánea tiene otra. Cada aplicación almacena su definición de un contacto en un silo único y aislado de información.
Hay varios problemas con los enfoques actuales para el almacenamiento de datos, entre los que se incluyen los siguientes:
- Los desarrolladores reinventan repetidamente las abstracciones de datos básicas.
- Varias aplicaciones no pueden compartir fácilmente datos comunes.
- La misma información reside en varias ubicaciones.
- El usuario escribe repetidamente la misma información.
- Las copias independientes de los datos se vuelven no sincronizadas.
- No hay notificaciones de cambio de datos.
¿Qué es WinFS?
WinFS es el nuevo sistema de almacenamiento en Longhorn. Mejora la plataforma Microsoft Windows de tres maneras. En primer lugar, le permite clasificar la información de varias maneras y relacionar un elemento de información con otro. En segundo lugar, proporciona un formato de almacenamiento común para la información recopilada diariamente, como la información que trata con personas, lugares, imágenes, etc. En tercer lugar, promueve el uso compartido de datos de información común en varias aplicaciones de varios proveedores.
WinFS es una plataforma de almacenamiento
WinFS es una plataforma de almacenamiento activa para organizar, buscar y compartir todo tipo de información. Esta plataforma define un modelo de datos enriquecido que permite usar y definir tipos de datos enriquecidos que puede usar la plataforma de almacenamiento. WinFS contiene numerosos esquemas que describen entidades reales como Imágenes, Documentos, Personas, Lugares, Eventos, Tareas y Mensajes. Estas entidades pueden ser bastante complejas. Por ejemplo, una persona puede tener varios nombres, varias direcciones de correo electrónico y físicas, una ubicación actual y mucho más.
Los proveedores de software independientes (ISV) también pueden definir sus propios tipos de datos nuevos y proporcionar su esquema a WinFS. Al permitir que WinFS administre problemas de almacenamiento complejos, un ISV puede concentrarse en desarrollar su lógica de aplicación única y aprovechar las instalaciones de almacenamiento más enriquecidas de WinFS para sus datos diarios y personalizados.
WinFS contiene un motor relacional que permite localizar instancias de tipos de almacenamiento mediante consultas relacionales eficaces. WinFS permite combinar estas entidades de almacenamiento de maneras significativas mediante relaciones. Un contacto puede ser miembro del grupo Empleado de una Organización mientras que simultáneamente es miembro del grupo Hogar para una dirección específica. Los ISV obtienen automáticamente la capacidad de buscar, replicar, proteger y establecer relaciones entre sus tipos de datos únicos, así como entre los tipos de datos predefinidos de Windows.
Esta estructura permite al usuario plantear preguntas al sistema y hacer que busque información en lugar de pedir al sistema que busque carpetas individualmente. Por ejemplo, puedes pedir a WinFS que busque todos los mensajes de correo electrónico de las personas de tu lista de amigos de mensajería instantánea para los que no tengas un número de teléfono. Mediante consultas relacionales, puede encontrar todos los miembros de un hogar para un empleado determinado con un cumpleaños en el mes actual.
WinFS también admite varios modelos de programación flexibles que permiten elegir la interfaz de programación de aplicaciones (API) adecuada para la tarea. Puede acceder al almacén mediante consultas relacionales tradicionales mediante lenguaje de consulta estructurado (SQL). Como alternativa, puede usar clases y objetos de .NET para acceder al almacén de datos. También puede usar api basadas en XML en el almacén de datos. WinFS también admite el acceso a datos a través de la API tradicional del sistema de archivos de Microsoft Win32. Incluso puede mezclar y coincidir, es decir, usar varias API para una sola tarea. Sin embargo, para la mayoría de los propósitos, los desarrolladores usarán las API de clase administrada para cambiar los datos en el almacén de WinFS. A menudo, será mucho más complejo realizar una actualización mediante instrucciones SQL sin procesar en comparación con el uso de las API de objetos.
Además, WinFS proporciona un conjunto de servicios de datos para supervisar, administrar y manipular los datos. Puede registrarse para recibir eventos cuando cambien determinados elementos de datos. Puede programar WinFS para replicar los datos en otros sistemas.
WinFS es un sistema de archivos
Para los datos tradicionales basados en archivos, como documentos de texto, pistas de audio y clips de vídeo, WinFS es el nuevo sistema de archivos de Windows. Normalmente, almacenará los datos principales de un archivo, la secuencia de archivos, como un archivo en un volumen NTFS. Sin embargo, cada vez que se llama a una API que cambia o agrega elementos con elementos de secuencia de archivos NTFS, WinFS extrae los metadatos de la secuencia y agrega los metadatos al almacén de WinFS. Estos metadatos describen información sobre la secuencia, como su ruta de acceso, además de cualquier información que WinFS pueda extraer de la secuencia. En función del contenido del archivo, estos metadatos pueden ser el autor (de un documento), el género (de un archivo de audio), las palabras clave (de un archivo PDF) y mucho más. WinFS sincroniza la secuencia de archivos residentes en NTFS y los metadatos residentes en WinFS. Las nuevas aplicaciones longhorn también pueden elegir almacenar sus secuencias de archivos directamente en WinFS. Se puede acceder a secuencias de archivos mediante la API del sistema de archivos Win32 existente o la nueva API de WinFS.
WinFS no es solo un sistema de archivos
Un sistema de archivos administra archivos y carpetas. Aunque WinFS administra archivos y carpetas, también administra todos los tipos de datos no basados en archivos, como contactos personales, calendarios de eventos, tareas y mensajes de correo electrónico. Los datos de WinFS pueden ser estructurados, semiestructurados o no estructurados. Los datos estructurados incluyen un esquema que además define qué son los datos y cómo se debe usar. Dado que WinFS es, en parte, un sistema relacional, aplica la integridad de los datos con respecto a la semántica, las transacciones y las restricciones.
WinFS no es solo un sistema relacional, tampoco. Admite almacenamiento jerárquico y almacenamiento relacional. Admite la devolución de datos como tipos estructurados y como objetos: tipos más comportamiento. Puede considerar WinFS un sistema de almacenamiento de datos jerárquico, relacional y orientado a objetos, aunque realmente contiene ciertos aspectos de cada uno de esos sistemas de almacenamiento tradicionales. WinFS se extiende más allá del sistema de archivos tradicional y del sistema de bases de datos relacionales. Es el almacén de todos los tipos de datos en la plataforma Windows más reciente.
WinFS y NTFS
Puede almacenar un archivo en el sistema de archivos NTFS tradicional o en el nuevo almacén de datos de WinFS como puede almacenar cosas en FAT32 o en CD-ROMs o en NTFS hoy mismo. Normalmente, un archivo almacenado en NTFS no es visible en WinFS. Las aplicaciones longhorn que usan las nuevas API de WinFS pueden acceder a los datos almacenados en WinFS o en NTFS. Además, las aplicaciones de Longhorn pueden seguir usando la API de Win32 para acceder a los datos almacenados en el sistema de archivos NTFS.
Promoción de archivos
Los archivos están en WinFS o no. Cualquier elemento que tenga un elemento de flujo de archivos puede participar en la promoción o disminución de nivel, que generalmente llamamos a control de metadatos. Cuando WinFS promueve un archivo, extrae los metadatos del contenido conocido del archivo NTFS y agrega los metadatos al almacén de datos de WinFS. El flujo de datos real del archivo permanece en el sistema de archivos NTFS. A continuación, puede consultar WinFS con respecto a los metadatos como si el archivo resida de forma nativa en WinFS. WinFS también detecta los cambios en el archivo NTFS y actualiza los metadatos dentro del almacén de datos de WinFS según sea necesario.
Importación y exportación de archivos
También puede importar un archivo a WinFS desde NTFS y exportar un archivo de WinFS a NTFS. La importación y exportación de un archivo mueve tanto el contenido del archivo como los metadatos. Después de importar o exportar, el nuevo archivo es completamente independiente del archivo original.
Modelo de programación de WinFS
El modelo de programación de WinFS incluye acceso a datos, manipulación de datos, extensibilidad de la clase de datos WinFS, sincronización de datos, notificaciones de cambios de datos y priorización de eventos. El acceso a datos y la manipulación de datos permiten crear, recuperar, actualizar y eliminar datos almacenados en WinFS y ejercer comportamientos específicos del dominio. La extensibilidad de la clase de datos permite ampliar esquemas winFS con campos personalizados y tipos personalizados. La sincronización de datos permite sincronizar los datos entre almacenes de WinFS y entre un almacén de WinFS y un almacén que no es de WinFS.
La parte superior de la jerarquía del modelo de datos de WinFS es un servicio winFS, que es simplemente una instancia de WinFS. Un nivel de la jerarquía del servicio es un volumen . Un volumen es el contenedor autónomo más grande de elementos. Cada instancia de WinFS contiene uno o varios volúmenes. Dentro de un volumen se elementos.
WinFS presenta el elemento como la nueva unidad de coherencia y operación, en lugar del archivo. El sistema de almacenamiento almacena elementos. Tiene una capacidad de consulta enriquecida sobre los elementos. Un elemento es efectivamente un tipo base del sistema de almacenamiento. Por lo tanto, un elemento tiene un conjunto de atributos de datos y proporciona una funcionalidad de consulta básica.
Las personas suelen organizar los datos en el mundo real según algún sistema que tenga sentido en un dominio determinado. Todos estos sistemas crean particiones de datos en grupos con nombre. WinFS modela esta noción con el concepto de una carpeta . Una carpeta es un tipo especial de elemento. Hay dos tipos de carpetas: carpetas de contención y carpetas virtuales.
Una carpeta de contención es un elemento que contiene vínculos a otros elementos y modelos el concepto común de una carpeta del sistema de archivos. Existe un elemento siempre que al menos un vínculo que contenga haga referencia a él. Tenga en cuenta que una carpeta de contención no contiene directamente los elementos presentes lógicamente en la carpeta, sino que contiene vínculos a esos elementos. Esto permite que varias carpetas de contención contengan el mismo elemento.
Una carpeta virtual es una colección dinámica de elementos. Es un conjunto con nombre de elementos. Puede enumerar el conjunto explícitamente o especificar una consulta que devuelva los miembros del conjunto. Una carpeta virtual especificada por una consulta es bastante interesante. Cuando se agrega un nuevo elemento al almacén que cumple los criterios de la consulta de una carpeta virtual, el nuevo elemento es automáticamente miembro de la carpeta virtual. Una carpeta virtual es un elemento. Conceptualmente, representa un conjunto de vínculos de no retención a elementos, como puede ver en la figura 4-1.
Figura 4-1. Jerarquía del modelo de datos de WinFS
A veces, debe modelar una noción muy restringida de contención; por ejemplo, un documento de Microsoft Word incrustado en un mensaje de correo electrónico es, en cierto sentido, enlazado más estrechamente a su contenedor que, por ejemplo, un archivo contenido en una carpeta. WinFS expresa esta noción mediante elementos incrustados. Un elemento incrustado es un tipo especial de vínculo dentro de un elemento (denominado Vínculo incrustado) que hace referencia a otro elemento. El elemento al que se hace referencia se puede enlazar o manipular solo dentro del contexto del elemento contenedor.
Por último, WinFS proporciona la noción de categorías de como una manera de clasificar elementos. Puedes asociar una o varias categorías a cada elemento de WinFS. WinFS, en efecto, etiqueta el nombre de categoría en el elemento. A continuación, puede especificar el nombre de categoría en las búsquedas. El modelo de datos de WinFS permite la definición de una jerarquía de categorías, lo que permite una clasificación similar a un árbol de datos.
Organización de la información
Todas estas características juntas permiten cinco maneras de organizar la información en WinFS:
- Organización jerárquica basada en carpetas. Con este enfoque, todavía tiene la estructura tradicional de la organización de carpetas jerárquicas y elementos. Todos los elementos de un almacén de datos de WinFS deben residir en un contenedor y uno de estos tipos de contenedor es una carpeta.
- Organización basada en tipos. Un elemento siempre es de un tipo determinado. Por ejemplo, tiene elementos de persona, elementos de foto, elementos de la organización y muchos otros tipos disponibles. Incluso puede crear nuevos tipos y almacenarlos en el almacén de datos de WinFS.
- Organización basada en propiedades de elemento. Puede ver los elementos que tienen una o varias propiedades establecidas en valores especificados. Esto es, en efecto, una vista de carpeta virtual con una consulta que devuelve los elementos con el valor especificado para las propiedades especificadas.
- Organización basada en relaciones. Puede recuperar elementos en función de su relación con otros elementos; por ejemplo, una persona puede ser miembro de una organización y se puede organizar o buscar en términos de esta relación.
- Organización basada en categorías. Puede crear y asociar cualquier número de palabras clave definidas por el usuario con un elemento. Posteriormente, puede recuperar los elementos que tienen un valor específico para una palabra clave asociada. Sin embargo, no podrá crear taxonomías de categorización, por lo que esta técnica de organización no es tan eficaz como los enfoques anteriores.
API de WinFS
WinFS proporciona tres API de acceso a datos: la API de WinFS administrada, la API de ADO.NET y la API de Win32. La API de WinFS es una API de "alto nivel" fuertemente tipada. ADO.NET proporciona una API de nivel inferior para trabajar con datos como XML o como tablas o filas. Con ADO.NET, puede acceder a los datos almacenados en WinFS mediante Transact-Structured lenguaje de consulta (T-SQL) y, cuando desee, recuperar datos en XML mediante la funcionalidad FOR XML de T-SQL. La API de Win32 permite el acceso a los archivos y carpetas almacenados en WinFS.
Es posible que prefiera usar varios patrones de acceso para resolver un problema. Por ejemplo, puede emitir una consulta T-SQL que devuelva un conjunto de contactos como objetos administrados del tipo de contacto de WinFS. Independientemente de la API que use, cada API manipula en última instancia los datos del almacén de WinFS mediante T-SQL.
En muchos casos, prefiere usar la API de WinFS administrada. Estas clases de .NET Framework realizan automáticamente la asignación de relación de objetos necesaria para traducir entre construcciones de programación orientadas a objetos y realizan el T-SQL necesario para lograr el acceso a datos de WinFS.
Uso de las clases WinFS administradas
Las clases administradas de WinFS residen en el espacio de nombres System.Storage
y sus espacios de nombres anidados. Muchas aplicaciones también usarán definiciones de tipos de WinFS desde el espacio de nombres System.Storage.Core
. Además, puede usar tipos de espacios de nombres más especializados. Por ejemplo, las clases administradas que manipulan la definición del sistema de un contacto residen en el espacio de nombres System.Storage.Contact
. Para simplificar, todos los ejemplos de código de este capítulo usarán el siguiente conjunto de declaraciones de using
:
using System.Storage;
using System.Storage.Core;
using System.Storage.Contact;
ItemContext
El almacén de WinFS consta de elementos organizados en carpetas y categorizados. El primer paso para trabajar con WinFS es identificar el conjunto de elementos con los que desea trabajar. Llamamos a este proceso enlacey el conjunto de elementos puede ser cualquiera de los siguientes:
- Un volumen completo (también conocido como la carpeta raíz )
- Subconjunto identificable de elementos de un volumen determinado, por ejemplo, una carpeta de contención determinada o carpeta virtual
- Un elemento individual
- Un recurso compartido de WinFS (que identifica un volumen, una carpeta, una carpeta virtual o un elemento individual)
Para enlazar a un conjunto de elementos, cree un objeto System.Storage.ItemContext
y conéctelo a un almacén de datos de WinFS. Use el método auxiliar de System.Storage.ItemContext.Open
estático para crear un objeto ItemContext
.
El código siguiente crea una ItemContext
que se conecta al volumen de WinFS local predeterminado. El valor predeterminado es \\nombre de equipo local\DefaultStore share:
System.Storage.ItemContext ctx = System.Storage.ItemContext.Open ();
§
ctx.Close();
Como alternativa, puede pasar una cadena al constructor para conectar el contexto del elemento a un almacén de WinFS específico. El código siguiente crea un contexto de elemento conectado a un recurso compartido de WinFS identificado por el recurso compartido \\machine\Legal Documents:
ItemContext ctx = null;
try {
ctx = ItemContext.Open (@"\machine\Legal Documents");
§
}
finally {
if (ctx != null) ctx.Dispose();
}
Asegúrese de cerrar o eliminar el objeto de contexto en cuanto termine de usarlo independientemente de las excepciones. Un ItemContext
usa recursos no administrados significativos (como una conexión al almacén) que debe liberar de forma oportuna. Para que los contextos de cierre sean lo más cómodos posible, la clase ItemContext
implementa la interfaz IDisposable
. Por lo tanto, puede usar la instrucción using
de C# como se muestra en el ejemplo siguiente para liberar estos recursos:
using (ItemContext ctx = ItemContext.Open (@"D:\MyStore")) {
§
}
Almacenar un nuevo elemento en un almacén de datos de WinFS
Cada elemento de un almacén de datos de WinFS debe ser miembro de una carpeta del almacén. Para obtener la raíz de la jerarquía de carpetas, llame al método estático extremadamente bien denominado System.Storage.Folder.GetRootFolder
. Sin embargo, también hay varios contenedores definidos por el sistema para almacenar datos específicos de la aplicación. A menudo se usa uno de los métodos estáticos de la clase UserDataFolder
para recuperar una carpeta en la que luego se colocan nuevos elementos.
Obtención de una carpeta
En el ejemplo siguiente, encontraré la carpeta Contactos personales del usuario actual si existe y la crearé cuando no exista. Tenga en cuenta que se trata de un ejemplo algo intrintable(el sistema crea automáticamente la carpeta Contactos personales de un usuario si no existe cuando el usuario inicia sesión por primera vez en un sistema), pero me da la oportunidad de mostrar cómo crear una carpeta esperada cuando no existe.
ItemContext ctx = ItemContext.Open ();
WellKnownFolder contactsFolder =
UserDataFolder.FindUsersWellKnownFolderWithType (ctx,
GeneralCategories.PersonalContactsFolder);
if (contactsFolder == null) {
//create the Personal Contacts folder
Folder userDataFolder = UserDataFolder.FindMyUserDataFolder (ctx);
WellKnownFolder subFolder = new WellKnownFolder (ctx);
CategoryRef category = new CategoryRef (ctx,
GeneralCategories.PersonalContactsFolder);
// Associate the PersonalContactsFolder category to the folder
subFolder.FolderType = category;
userDataFolder.AddMember (subFolder);
ctx.Update();
}
El código anterior hace una serie de cosas interesantes. En primer lugar, intento localizar una carpeta existente contenida en la jerarquía de carpetas de datos personales del usuario. No estoy buscando la carpeta por un nombre conocido. En su lugar, estoy localizando la carpeta dentro del árbol de datos personales del usuario que se ha asociado anteriormente con la categoría conocida PersonalContactsFolder
. El shell muestra esta carpeta al seleccionar Mis contactos.
Normalmente, esta carpeta ya existe, pero cuando no lo hace, recupero la carpeta raíz de la jerarquía de datos del usuario. Creo un nuevo elemento, de tipo WellKnownFolder
y, a continuación, creo una referencia a una categoría conocida, la categoría PersonalContactsFolder
. A continuación, he establecido el tipo de la nueva carpeta en el tipo de categoría PersonalContactsFolder
y, por último, agrego la nueva carpeta a su carpeta contenedora, la carpeta raíz de datos personales del usuario. WinFS no guarda ningún cambio en el almacén de datos hasta que se llama a Update
en el contexto del elemento (lo que he olvidado hacer regularmente).
Por supuesto, esta es la forma detallada de encontrar la carpeta Contactos personales. Quería mostrarte cómo funcionan las cosas. Normalmente, usaría el código siguiente en su lugar. El método FindMyPersonalContactsFolder
busca la carpeta existente.
WellKnownFolder userDataFolder =
UserDataFolder.FindMyPersonalContactsFolder (ctx);
Crear un nuevo elemento
Como ahora tengo la carpeta Contactos personales, parece apropiado crear un nuevo contacto en la carpeta. En el ejemplo siguiente, crearé varios contactos de persona y los agregaré a la carpeta :
Person[] CreateFriends (ItemContext ctx) {
string[] GivenNames = { "Monica", "Rachel", "Chandler",
"Joey", "Phoebe", "Ross"};
string[] SurNames = { "Uchra", "Emerald", "Ranier",
"Fibonacci", "Smorgasbord", "Uchra"};
Person[] Friends = new Person [GivenNames.Length];
for (int index = 0; index < GivenNames.Length; index++) {
string linkName = GivenNames[index] + " " + SurNames[index];
Person p = Person.CreatePersonalContact (ctx, linkName);
Friends[index] = p;
p.DisplayName = linkName;
FullName fn = p.GetPrimaryName ();
fn.GivenName = GivenNames[index];
fn.Surname = SurNames[index];
}
ctx.Update ();
}
El código anterior usa el método estático Person.CreatePersonalContact
. Este método
- Crea un nuevo elemento Person en el contexto de elemento especificado.
- Crea una nueva relación de
FolderMember
con el nombre especificado que hace referencia a la persona - Agrega la relación
FolderMember
a la colecciónRelationship
delPersonalContactsFolder
Posteriormente actualizo las propiedades DisplayName
, GivenName
y Surname
del elemento Person. Como siempre, llamo a Update
en el contexto del elemento para guardar los cambios en el almacén de datos.
Echemos un vistazo más detenidamente al método CreatePersonalContact
. Es equivalente a lo siguiente:
// Find the PersonalContacts folder
WellKnownFolder contactsFolder =
UserDataFolder.FindUsersWellKnownFolderWithType (ctx,
GeneralCategories.PersonalContactsFolder);
// Create a new Person item
Person p = new Person (ctx);
// Need a folder relationship that references the new Person
FolderMember fm = new FolderMember (p, linkName);
folder.Relationships.Add (fm);
ctx.Update ();
Elementos de relación
WinFS define un modelo de datos de relación que permite relacionar elementos entre sí. Al definir el esquema de un tipo de datos, puede definir cero o más relaciones como parte del esquema. Por ejemplo, el esquema Folder define la relación FolderMember. El esquema de la organización define la relación de Employee
. Para cada una de estas relaciones definidas, hay una clase que representa la propia relación. Esta clase se deriva de la clase Relationship
y contiene miembros específicos del tipo de relación. También hay una clase de colección "virtual" fuertemente tipada. Esta clase se deriva de VirtualRelationshipCollection
y permite crear y eliminar instancias de relación.
Una relación relaciona un elemento de origen con un elemento de destino. En el ejemplo anterior, la carpeta Contactos personales era el elemento de origen y el elemento Person era el elemento de destino. La relación FolderMember
indica básicamente que el elemento Person se relaciona con la carpeta Contactos personales como miembro de la carpeta.
Cuando se define una relación, se define si la relación mantiene el elemento de destino en existencia (un mantener la relacióno no mantiene el elemento de destino en existencia), una relación de referencia . Al crear una relación de retención con un elemento de destino, WinFS incrementa un recuento de referencias en el elemento de destino. Cuando WinFS elimina una relación de retención, disminuye el recuento de referencias del elemento de destino. Ya no existe un elemento en el almacén cuando su recuento de referencias alcanza cero. WinFS nunca modifica el recuento de referencias del destino al crear o destruir una relación de referencia con el destino. Por lo tanto, el elemento de destino puede desaparecer del almacén cuando su recuento de referencias alcanza cero y la relación podría hacer referencia a un elemento ya no existente.
WinFS define la relación de FolderMember
como una relación de retención. La mayoría de las demás clases de relación son relaciones de referencia.
Elementos de carpeta
Ahora que sabe acerca de los elementos link, puedo refinar mi descripción de elementos de carpeta. Una carpeta es un elemento de WinFS que tiene una colección de elementos Link. El destino de cada elemento Link de la colección es un miembro de la carpeta. La propiedad Folder.Members
representa esta colección de vínculos.
Tenga en cuenta que esto proporciona una carpeta WinFS mucho más flexibilidad que las carpetas tradicionales del sistema de archivos. Los miembros de una carpeta pueden ser elementos de archivo y no de archivo. Varios vínculos a un elemento determinado pueden residir simultáneamente en muchas carpetas. En otras palabras, varias carpetas pueden contener el mismo elemento.
Otros tipos de elementos
Por lo general, crea otros tipos de elementos en el almacén de WinFS como hizo en los ejemplos anteriores. Cada tipo tiene ocasionalmente su propio patrón de uso especial. Por ejemplo, podemos tener organizaciones como miembros de nuestra carpeta Contactos personales, por lo que vamos a crear una:
Organization cp = FindOrCreateOrganization (ctx, "Main Benefit");
§
Organization FindOrCreateOrganization (ItemContext ctx, string orgName) {
Organization o =
Organization.FindOne (ctx, "DisplayName='" + orgName + "'");
if (o == null) {
Folder Pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
o = new Organization (ctx);
o.DisplayName = orgName;
Folder pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
pcf.AddMember (o, o.DisplayName.ToString ());
ctx.Update ();
}
return o;
}
Ahora vamos a agregar un empleado a esa organización:
enum Names { Monica, Rachel, Chandler, Joey, Phoebe, Ross }
§
Person[] Friends = CreateFriends (ctx);
Organization cp = FindOrCreateOrganization (ctx, "Main Benefit");
AddEmployeeToOrganization (ctx, Friends [(int)Names.Rachel],
cp);
§
void AddEmployeeToOrganization (ItemContext ctx, Person p, Organization o) {
EmployeeData ed = new EmployeeData (ctx);
ed.Name = p.DisplayName;
ed.Target_Key = p.ItemID_Key;
o.Employees.Add (ed);
ctx.Update ();
}
De forma similar, podemos crear hogares en nuestras carpetas contactos personales. Tenga en cuenta que un hogar no implica una familia. Un hogar podría ser un grupo de compañeros de habitación. WinFS tiene un esquema adicional para las familias, pero lo dejaré como ejercicio para el lector.
CreateHousehold (ctx, Friends [(int) Names.Chandler],
Friends [(int) Names.Joey]);
CreateHousehold (ctx, Friends [(int) Names.Monica],
Friends [(int) Names.Rachel]);
§
void CreateHousehold (ItemContext ctx, Person p1, Person p2) {
Household h = new Household (ctx);
h.DisplayName = p1.GetPrimaryName().GivenName + " and " +
p2.GetPrimaryName().GivenName + " household";
Folder pcf = UserDataFolder.FindMyPersonalContactsFolder (ctx);
pcf.AddMember (h, h.DisplayName.ToString ());
// Add first person to the household
HouseholdMemberData hhmd = new HouseholdMemberData (ctx);
hhmd.Name = p1.DisplayName;
hhmd.Target_Key = p1.ItemID_Key;
h.HouseholdMembers.Add (hhmd);
// Add second person to the household
hhmd = new HouseholdMemberData (ctx);
hhmd.Name = p2.DisplayName;
hhmd.Target_Key = p2.ItemID_Key;
h.HouseholdMembers.Add (hhmd);
}
En el ejemplo anterior se usa un concepto que aún no he analizado. Tenga en cuenta el uso de la propiedad ItemID_Key
en esta línea de código:
hhmd.Target_Key = p1.ItemID_Key;
Básicamente, el valor de ItemID_Key
es otra manera de hacer referencia a un elemento en el almacén de WinFS, por lo que vamos a examinar las formas de buscar elementos en el almacén.
Cómo buscar elementos
Por supuesto, no hace mucho bien colocar elementos en un almacén de datos si no puede encontrarlos fácilmente. La clase ItemContext
contiene métodos de instancia que puede usar para recuperar elementos en un almacén de datos de WinFS. Especifique el tipo de elemento que se va a buscar y las restricciones especiales que deben cumplir los elementos devueltos. Además, cada clase de elemento (por ejemplo, Person
, File
, Folder
, etc.) también contiene métodos estáticos que permiten buscar elementos de ese tipo en particular.
El método FindAll
devuelve uno o varios elementos que coinciden con los criterios especificados. El método de instancia de ItemContext.FindAll
requiere que especifique el tipo de los elementos que se van a buscar. Además, puede especificar opcionalmente criterios de búsqueda para restringir el ámbito de búsqueda. Por ejemplo, el código siguiente busca todos los elementos Person que tienen una propiedad DisplayName
cuyo valor comienza por "Brent".
FindResult res = ctx.FindAll (typeof(Person), "DisplayName='Brent%'");
foreach (Person p in res) {
// Use the Person item somehow
}
Como alternativa, podría usar el método estático FindAll
de la clase Person
como este:
FindResult res = Person.FindAll (ctx, "DisplayName='Brent%'");
foreach (Person p in res) {
// Use the Person item somehow
}
En ambos ejemplos, el método FindAll
siempre devuelve una colección de los elementos que coinciden con el tipo y los criterios especificados. Esta colección puede no contener ningún elemento, pero no recibe una referencia nula para el FindResult
. Por lo tanto, siempre recorre en iteración la colección para obtener los elementos encontrados.
Cuando sepa que solo un solo elemento coincidirá con el tipo solicitado y los criterios de filtro especificados, puede usar el método FindOne
. Sin embargo, tenga cuidado: el método FindOne
produce una excepción cuando encuentra más de un elemento que coincida con la solicitud.
Person p = Person.FindOne (ctx, "DisplayName='Brent Rector'");
El segundo parámetro de cadena es una expresión de filtro que permite especificar restricciones adicionales que deben satisfacer los elementos devueltos. El formato básico de la expresión de filtro es una cadena con el formato "<propertyName> <operator> <propertyValue>
".
WinFS llama a la expresión una expresión OPath
. La sintaxis es similar, aunque no idéntica, a la sintaxis de expresión de XPath
usada para identificar elementos de un documento XML. Este fragmento de código devuelve todos los elementos de archivo de los archivos con una extensión de archivo "doc" o "txt":
FindResult Files = File.FindAll (ctx, "Extension='doc' || Extension='txt'");
Estas expresiones pueden ser bastante complejas. Por ejemplo, la siguiente declaración devuelve todos los elementos Person que representan a los empleados de un empleador con el DisplayName
de "Principal Beneficio":
string pattern = "Source(EmployeeOf).DisplayName='Main Benefit'";
FindResult result = Person.FindAll (ctx, pattern);
Aquí está otra. Quiero que los elementos person donde el apellido no sea "Ranier" y las direcciones de correo electrónico no terminen con ".edu".
string filter = "PersonalNames[Surname!='Ranier'] &&
!(PersonalEmailAddresses[Address like '%.edu'])");
FindResult result = Person.FindAll (ctx, filter);
Identificación de un elemento específico
Con frecuencia, necesita crear referencias a elementos en el almacén de WinFS. Finalmente, usará estas referencias para buscar el elemento adecuado. Anteriormente en este capítulo, le mostré cómo usar un vínculo para hacer referencia a un elemento. Los vínculos usan una identidad basada en cadenas descriptivo para la referencia y este nombre de cadena debe ser único dentro de la carpeta contenedora del vínculo. En otras palabras, necesita la carpeta y uno de sus vínculos contenidos para identificar el elemento al que se hace referencia.
Sin embargo, puede crear varios vínculos con el mismo nombre de cadena descriptivo siempre que agregue los vínculos a carpetas diferentes para que todos los nombres de una sola carpeta permanezcan únicos. Tenga en cuenta que estos varios vínculos con el mismo nombre de texto descriptivo no tienen que hacer referencia al mismo elemento de destino. Podrían, pero no tienen que hacerlo.
En tales casos, la búsqueda de todos los vínculos con un nombre de texto descriptivo específico (mediante FindAll
, por ejemplo) devolverá varios resultados. A continuación, deberá examinar el origen de cada vínculo para determinar la carpeta contenedora y, a continuación, determinar qué vínculo hace referencia al elemento deseado.
Necesitamos una manera de hacer referencia a cualquier elemento arbitrario de la tienda, por ejemplo, supongamos que quiero el elemento 3.287 en la tienda. Afortunadamente, puedes hacerlo exactamente.
Buscar un elemento por ItemID_Key valor
WinFS asigna a cada elemento recién creado un número de identificación basado en GUID, conocido como su propiedad ItemID_Key
. En la práctica, es muy probable que un valor de ItemID_Key
sea único en todos los volúmenes de WinFS; Sin embargo, WinFS sigue tratando este identificador como si fuera único solo dentro de un volumen. Puede usar este valor único de volumen para identificar cualquier elemento de un volumen de WinFS.
Item GetItem (ItemContext ctx, SqlBinary itemID_Key) {
// Convert itemID_Key to a string for use in the OPath filter
string hexItemID_Key = BitConverter.ToString (itemID_Key.Value);
hexItemID_Key = "'0x" + hexItemID_Key.Replace ("-", String.Empty) + "'";
// Build an opath filter expression.
string query = "ItemID_Key=" + hexItemID_Key;
return Item.FindOne (ctx, query);
}
Características comunes
La API de WinFS proporciona varias características en todo el espectro de clases de datos. Estas características son
- Asincronía
- Transacciones
- Notificaciones
- Compatibilidad con blobs o secuencias
- Cursor y paginación
Asincronía
La API de WinFS permite ejecutar consultas de forma asincrónica. La API de WinFS usa los patrones de modelo de programación asincrónica estándar de .NET.
Transacciones
El almacén de WinFS es un almacén transaccional. Por lo tanto, WinFS permite realizar actualizaciones transaccionales en el almacén mediante los métodos BeginTransaction
, CommitTransaction
y AbortTransaction
en el objeto ItemContext
, como se muestra en el ejemplo siguiente:
using (ItemContext ctx = ItemContext.Open()) {
using (Transaction t = ctx.BeingTransaction()) {
Person p = Person.FindOne (ctx,
"PersonalNames[GivenName='Chandler' And SurName='Bing']" );
Household h = Household.FindOne (ctx,
"DisplayName = 'Chandler and Joey Household'");
p.PersonalEAddresses.Add (new TelephoneNumber ("202", "555-1234"));
p.Save ();
h.Members.Add (p);
h.Save ();
t.Commit ();
}
}
Notificaciones
El servicio de notificaciones de WinFS usa los conceptos de suscripciones a corto y largo plazo. Una suscripción a corto plazo dura hasta que una aplicación cancela la suscripción o se cierra la aplicación. Una suscripción a largo plazo sobrevive a los reinicios de la aplicación. La API de WinFS monitores son un conjunto de clases que permiten a las aplicaciones recibir notificaciones selectivas de los cambios en el almacén de WinFS y proporcionar información de estado que la aplicación puede conservar para admitir escenarios de suspensión y reanudación.
La clase Watcher
puede notificar a la aplicación los cambios en distintos aspectos de los objetos WinFS, incluidos los siguientes:
- Cambios de elemento
- Cambios de elementos incrustados
- Cambios de extensión de elemento
- Cambios de relación
Cuando un monitor genera un evento, envía datos de estado del monitor con la notificación de eventos. La aplicación puede almacenar estos datos de estado para su recuperación posterior. Posteriormente, puedes usar estos datos de estado del monitor para indicar a WinFS que quieres recibir eventos para todos los cambios que se produjeron después de generar el estado.
El modelo de programación de monitor también permite deshabilitar cualquier combinación de eventos agregados, modificados y eliminados. También se puede configurar para generar un evento inicial que simula la adición de todos los elementos existentes, extensiones de elemento, relaciones, etc.
El diseño del monitor de WinFS se divide en las clases descritas en la tabla siguiente.
Clase | Propósito/Descripción |
---|---|
WatcherOptions |
Clase para especificar el ámbito inicial y las opciones de granularidad para StoreWatcher |
StoreWatcher |
La clase quintaesential para ver los elementos de WinFS, los elementos incrustados, las extensiones de elemento y las relaciones |
WatcherState |
Objeto opaco que se puede usar para inicializar un StoreWatcher |
ChangedEventHandler |
Clase que define el controlador de eventos al que llamarán StoreWatcher |
ChangedEventArgs |
Clase pasada como argumento a ChangedEventHandler |
ItemChangeDetail |
Clase base que proporciona detalles de cambio pormenorizados para eventos de elementos |
ItemExtensionChangeDetail |
Clase derivada de ItemChangeDetail que proporciona detalles de cambio adicionales específicos de los eventos de extensión de elemento |
RelationshipChangeDetail |
Clase derivada de ItemChangeDetail que proporciona detalles de cambio adicionales específicos de los eventos de relación |
La clase StoreWatcher
se usa para crear un monitor para algún elemento en el almacén de WinFS. La instancia de StoreWatcher
generará eventos cuando cambie el elemento especificado. Puede especificar el tipo de elemento y jerarquía que se va a inspeccionar. De forma predeterminada, un monitor
- No genera un evento inicial para establecer el estado actual
- Inspecciona el elemento y la jerarquía (incluidos los elementos secundarios inmediatos) para cualquier cambio.
- Genera eventos add, remove y modify en este elemento o en cualquier elemento secundario de toda la jerarquía.
- Genera eventos add, remove y modify para las extensiones de elemento de este elemento o cualquier elemento secundario de toda la jerarquía.
- Genera eventos add, remove y modify para las relaciones en las que este elemento o cualquier elemento secundario de toda la jerarquía es el origen de la relación.
Dado que, de forma predeterminada, un monitor supervisa los cambios en el elemento especificado y sus descendientes, es posible que desee especificar WatchItemOnly
como opción de monitor. En el ejemplo siguiente se comprueban los cambios solo en el elemento Person ubicado:
Person p = Person.FindOne (ctx,
"PersonalNames[GivenName='Rachel' and Surname='Emerald'");
StoreWatcher w = new StoreWatcher ( p, WatcherOptions.WatchItemOnly );
Una carpeta es solo otro elemento de WinFS. Observa los cambios en una carpeta de la misma manera que lo hace para una persona:
Folder f = · · ·
StoreWatcher w = new StoreWatcher (f, <WatcherOptions>);
También puede observar los cambios en una relación especificada de un elemento:
Person p = · · ·
StoreWatcher w = new StoreWatcher (p, typeof(HouseholdMember),
<WatcherOptions> );
w.ItemChanged += new ChangedEventHandler (ItemChangedHandler);
w.Enabled = true;
// Change notifications now arrive until we unsubscribe from the event
§
// Now we unsubscribe from the event
w.ItemChanged -= new ChangedEventHandler (ItemChangedHandler);
w.Dispose ();
§
// The change notification handler
void ItemChangedHandler (object source, ChangedEventArgs args) {
foreach (ItemChangeDetail detail in args.Details) {
switch (typeof(detail)) {
case ItemExtensionChangeDetail:
// handle added + modified + removed events for Item Extension
break;
case RelationshipChangeDetail:
// handle added + modified + removed events for Relationship
break;
default:
case ItemChangeDetail:
// handle added + modified + removed events for Item or Embedded Item
HandleItemChangeDetail (detail);
break;
}
}
|
void HandleItemChangeDetail (ItemChangeDetail detail) {
switch (detail.ChangeType) {
case Added: // handle added event
break;
case Modified: // handle modified event
break;
case Removed: // handle modified event
break;
}
}
Compatibilidad con blobs y secuencias
Las API de compatibilidad con blobs y secuencias siguen en flujo en el momento de redactar este documento. Consulte la documentación para obtener la información más reciente sobre cómo acceder a blobs y secuencias en el almacén de WinFS.
Cursor y paginación
Los distintos métodos de Find
de las clases WinFS pueden devolver una colección (potencialmente) grande de objetos. Esta colección es el equivalente de un conjunto de filas en el mundo de la base de datos. Las aplicaciones de base de datos tradicionales usan un cursor paginado para navegar de forma eficaz dentro de un conjunto de filas grande. Este cursor hace referencia a una sola fila (un de cursor fino) o un conjunto de filas (una página de cursor). La idea es que las aplicaciones recuperan el valor de filas de una página a la vez; también pueden identificar una fila dentro de la página para la actualización y eliminación posicionadas. La API de WinFS proporciona abstracciones similares al desarrollador para tratar colecciones grandes.
De forma predeterminada, una operación de búsqueda proporciona un cursor dinámico, desplazable y de solo lectura sobre la colección devuelta. Una aplicación puede tener un cursor de manguera de fuego para un rendimiento máximo. Un cursor de manguera de fuego es un cursor de solo avance. La aplicación puede recuperar una página de filas a la vez, pero la siguiente operación de recuperación comenzará con el conjunto posterior de filas; no puede volver atrás y volver a recuperar filas. En cierto sentido, las filas fluyen de la tienda a la aplicación como el agua de una manguera de fuego, por lo que el nombre.
La propiedad CursorType
de la clase FindParameters
permitirá a una aplicación elegir entre una manguera de incendios y un cursor desplazable. Tanto para la manguera de fuego como para los cursores desplazables, la aplicación puede establecer un tamaño de página mediante la propiedad PageSize
de la clase FindParameters
. De forma predeterminada, el tamaño de página se establece en 1.
Enlace de datos
Puede usar las clases de datos de WinFS como orígenes de datos en un entorno de enlace de datos. Las clases winFS implementan IDataEntity
(para objetos únicos) y IDataCollection
(para colecciones). La interfaz IDataEntity
proporciona notificaciones al destino de enlace de datos de los cambios en las propiedades del objeto de origen de datos. La interfaz IDataCollection
permite determinar el tipo base de un objeto en una colección polimórfica. También permite recuperar un System.Windows.Data.CollectionManager
, que navega por las entidades de datos de la colección y proporciona una vista (por ejemplo, criterio de ordenación o filtro) de la colección. Discuta el enlace de datos en detalle en el capítulo 5.
Seguridad
El modelo de seguridad de WinFS concede fundamentalmente un conjunto de Rights
a un Principal
en una Item
de las siguientes maneras:
- La seguridad se establece en el nivel de
Items
. - Un conjunto de derechos se puede conceder a un principio de seguridad en un
Item
. Este conjunto incluye: READ, WRITE, DELETE, EXECUTE (para todos los elementos), CREATE_CHILD, ADMINISTER y AUDIT. (Los derechos adicionales se pueden conceder en los elementos folder). - Los usuarios y las aplicaciones son los principios de seguridad. Los derechos de aplicación reemplazan los derechos de usuario. Cuando una aplicación no tiene permiso para eliminar un contacto, un usuario no puede eliminarlo a través de la aplicación independientemente de los permisos del usuario.
- La seguridad se establece mediante reglas; cada regla es un
Grant
y se aplica a un triplete: (<ItemSet, PrincipalSet, RightSet>
). - Las reglas se almacenan como
Items
.
Obtener derechos en un elemento
Cada clase de elemento de WinFS tiene un método denominado GetRightsForCurrentUser
, que devuelve el conjunto de derechos ,READ, WRITE, DELETE, etc., que el usuario actual tiene en el elemento especificado. Además, el método devuelve el conjunto de métodos que WinFS permite al usuario ejecutar.
Establecer derechos en un elemento
WinFS usa un tipo de elemento especial, SecurityRule
, para almacenar información de permisos en Items
. Por lo tanto, establecer y cambiar derechos no es diferente de manipular ningún otro Item
en WinFS. Este es un ejemplo de código que muestra cómo establecer derechos en un elemento de carpeta:
using (ItemContext ctx = ItemContext.Open("\\localhost\WinFS_C$")) {
SecurityRule sr = new SecurityRule (ctx);
sr.Grant = true;
// set permission on items under folder1 including folder1
sr.AppliesTo = <folder1's Identity Key>;
sr.Condition = acl1; // a DACL
sr.Save();
}
Extensión de la API de WinFS
Cada clase WinFS integrada contiene métodos estándar como Find*
y tiene propiedades para obtener y establecer valores de campo. Estas clases y métodos asociados forman la base de las API de WinFS y permiten aprender a usar una clase y saber, en general, cómo usar muchas otras clases de WinFS. Sin embargo, aunque el comportamiento estándar es útil, cada tipo de datos específico necesita comportamientos adicionales específicos del tipo.
Comportamientos de dominio
Además de estos métodos estándar, cada tipo winFS normalmente tendrá un conjunto de métodos específicos del dominio únicos para ese tipo. (En realidad, la documentación de WinFS a menudo hace referencia a definiciones de tipos como esquema, lo que refleja el patrimonio de la base de datos de WinFS). WinFS hace referencia a estos métodos específicos del tipo como comportamientos de dominio. Por ejemplo, estos son algunos comportamientos de dominio en el esquema de contactos:
- Determinar si una dirección de correo electrónico es válida
- Dada una carpeta, obtención de la colección de todos los miembros de la carpeta
- Dado un identificador de elemento, obtención de un objeto que representa este elemento
- Dado a una persona, obteniendo su estado en línea
- Creación de un nuevo contacto o un contacto temporal con funciones auxiliares
comportamientos de Value-Added
Las clases de datos con comportamientos de dominio forman una base en la que se basan los desarrolladores de aplicaciones. Sin embargo, no es posible ni deseable que las clases de datos expongan todos los comportamientos concebibles relacionados con esos datos.
Puede proporcionar nuevas clases que amplíen la funcionalidad base que ofrecen las clases de datos de WinFS. Para ello, escriba una clase cuyos métodos toman una o varias de las clases de datos de WinFS como parámetros. En el ejemplo siguiente, el OutlookMainServices
y el WindowsMessageServices
son clases hipotéticas que usan las clases estándar MailMessage
y Person
winFS:
MailMessage m = MailMessage.FindOne (…);
OutlookEMailServices.SendMessage(m);
Person p = Person.FindOne (…);
WindowsMessagerServices wms = new WindowsMessagerServices(p);
wms.MessageReceived += new MessageReceivedHandler (OnMessageReceived);
wms.SendMessage("Hello");
A continuación, puede registrar estas clases personalizadas con WinFS. Los datos de registro se asociarán a los metadatos de esquema que WinFS mantiene para cada tipo de WinFS instalado. WinFS almacena los metadatos de esquema como elementos de WinFS; Por lo tanto, puede actualizar, consultar y recuperarlo como lo haría con todos los demás elementos de WinFS.
Especificar restricciones
El modelo de datos de WinFS permite restricciones de valor en los tipos. WinFS evalúa y aplica estas restricciones al agregar elementos al almacén. Sin embargo, a veces desea comprobar que los datos de entrada satisfacen sus restricciones sin incurrir en la sobrecarga de un recorrido de ida y vuelta al servidor. WinFS permite al autor del esquema o tipo decidir si el tipo admite la comprobación de restricciones del lado cliente. Cuando un tipo admite la validación del lado cliente, el tipo tendrá un método validate al que puede llamar para comprobar que un objeto satisface las restricciones especificadas. Tenga en cuenta que, independientemente de si el desarrollador llama al método Validate
, WinFS sigue comprobando las restricciones en el almacén.
Uso de la API de WinFS y SQL
La API de WinFS permite a un desarrollador acceder al almacén de WinFS mediante conceptos conocidos de Common Language Runtime (CLR). A lo largo de este capítulo, he usado el siguiente patrón de codificación para el acceso a WinFS:
- Enlazar a un
ItemContext
. - Busque los elementos deseados.
- Actualice los elementos.
- Vuelva a guardar todos los cambios en el almacén.
El paso 2 es básicamente una consulta al almacén. La API de WinFS usa una sintaxis de expresión de filtro basada en OPath
para especificar estas consultas. En muchos casos, el uso de expresiones de filtro debe ser suficiente para la mayoría de las tareas. Sin embargo, habrá casos en los que el desarrollador querrá usar toda la eficacia y flexibilidad de SQL.
Las siguientes funcionalidades están presentes en SQL, pero no están disponibles al usar una expresión de filtro:
- Aggregation (
Group By
,Having
,Rollup
) - Proyección (incluidas las expresiones select calculadas, distinct, IdentityCol, RowGuidCol)
- Para XML
- Unión
- Opción
- Combinación derecha, completa o cruzada
- Selecciones anidadas
- Combinación a una tabla que no es winFS
Por lo tanto, es esencial que un desarrollador de WinFS pueda realizar una transición sin problemas entre la API SQLClient y la API de WinFS, usando una o la otra en varios lugares del código.
Agregar y agrupar con SQL y, a continuación, usar la API de WinFS
Un propietario de pequeñas empresas, Joe, quiere determinar quiénes son sus 10 clientes principales y enviar cestas de regalos a ellos. Supongamos que Customer es un tipo de elemento esquematizado. Esto significa que un ISV ha proporcionado un esquema para el tipo customer a WinFS y, por lo tanto, también significa que un almacén de WinFS ahora puede contener elementos customer. Un elemento Customer tiene un vínculo de retención a un tipo de elemento de pedido esquematizado. Order Item tiene una colección incrustada de pedidos de línea, como se indica a continuación:
1. using (ItemContext ctx = ItemContext.Open()) {
2.
3. SqlCommand cmd = ctx.CreateSqlCommand();
4. cmd.CommandText =
5. "select object(c) from Customers c inner join (" +
6. "select top 10 C.ItemId, sum(p.price) " +
7. "from Customers C" +
8. "inner join Links L on L.SourceId = C.ItemId" +
9. "inner join Orders O on L.TargetId = O.ItemId" +
10. "cross join unnest(O.LineOrders) " +
11. "group by C.ItemId" +
12. "order by sum(p.price)) t ON c.ItemId = t.ItemId";
13.
14. SqlDataReader rdr = cmd.ExecuteReader();
15.
16. GiftBasketOrder gbOrder = new GiftBasketOrder(Ö);
17.
18. while (rdr.Read()) {
19. Customer c = new Customer((CustomerData) rdr.GetValue(0));
20. // add the customer to gbOrder's recipient collection
21. gbOrder.Recipients.Add(c);
22. }
23.
24. // send the order. The ISV's GiftBasketOrder can easily pull out
25. // customer info such as shipping address from the Customer object
26. gbOrder.Send();
27. }
En la línea 1 de este ejemplo, abra un contexto para la raíz del volumen del sistema. En la línea 3, creo un objeto de comando SQL que después uso para ejecutar una consulta SQL en el almacén de WinFS. Este objeto de comando reutiliza la conexión utilizada por el contexto del elemento. Las líneas 4 a 12 construyen la consulta y la línea 14 ejecuta la consulta. La consulta devuelve los 10 clientes principales de la siguiente manera: la instrucción SELECT de las líneas 6 a 12 genera una tabla agrupada que contiene el valor total de los pedidos de cada cliente; La cláusula ORDER BY de la línea 12, combinada con el modificador TOP 10 de la línea 6, selecciona solo los 10 principales clientes de esta tabla agrupada.
La clase GiftBasketOrder
es una clase personalizada que usa la API de WinFS Customer
objeto. Creo una instancia de GiftBasketOrder
en la línea 16.
La línea 19 usa el SQLDataReader
para leer la primera columna del conjunto de filas devuelto y convertirlo en un objeto CustomerData
.
Al definir un nuevo tipo en WinFS (conocido como crear un nuevo esquema), realmente está definiendo dos tipos: la clase administrada y el formato persistente del almacén de WinFS de la clase. WinFS siempre agrega el data sufijo al nombre de la clase para crear el nombre del tipo del almacén. Por lo tanto, por ejemplo, al definir un nuevo tipo de cliente que reside en el almacén de WinFS, WinFS crea el tipo definido por el usuario (UDT) en paralelo CustomerData
WinFS.
La primera columna del conjunto de filas contiene el objeto CustomerData
del almacén. Paso este objeto al constructor de la clase Customer
y el constructor inicializa el nuevo objeto desde el objeto CustomerData
. Este ejemplo es típico de usar udT de almacén para construir objetos de API de WinFS.
La línea 24 agrega el cliente a la colección Recipients
del GiftBasketOrder
.
Por último, uso el método Send
en gbOrder para "enviar" este pedido.
Vaya a la API y, a continuación, agregue en SQL.
Supongamos que desea encontrar el salario medio (durante un período de 10 años) para el CEO de cada empresa de mi cartera. Use las suposiciones siguientes:
- Tengo una carpeta denominada Companies In My Portfolio, que contiene elementos de tipo Organization.
-
EmployeeData
es una relación basada en vínculos y tiene unYearlyEmploymentHistory
que tiene el año y el salario de ese año.
1. using (ItemContext ctx = ItemContext.Open(@"Companies In My Portfolio")) {
2.
3. SqlCommand cmd = ctx.CreateCommand();
4. cmd.CommandText =
5. "select avg( Salary ) from Links l cross apply " +
6. "( select Salary from unnest( convert(" +
7. "EmployeeData,l.LinkCol)::YearlyEmploymentHistory )" +
8. "where Year >= '1993' ) where l.LinkID = @LinkID";
9.
10. SqlParameter param = new SqlParameter ("@LinkID", SqlDbType.BigInt);
11. cmd.Parameters.Add (param);
12.
13. Folder f = Folder.FindByPath (ctx, ".");
14.
15. FindResult orgs = f.GetMembersOfType (typeof(Organization));
16. foreach (Organization o in orgs) {
17. EmployeeData ed = EmployeeData.FindEmployeeInRole (o,
18. Organization.Categories.CeoRole);
19. param.Value = ed.Link.LinkID;
20. SqlDataReader rdr = cmd.ExecuteReader ();
21. rdr.Read ();
22. Console.WriteLine ("{0} ${1}",
23. ((Person)ed.Target).PersonalNames[0].FullName, rdr.GetFloat(0) );
24. rdr.Close ();
25. }
26. }
La línea 1 abre un contexto para las acciones de Companies In My Portfolio WinFS. Las líneas 3 a 11 crean una consulta SQL parametrizada que puedo usar en el contexto de la carpeta. Esta consulta devuelve el salario medio de un empleado determinado (representado por el parámetro @LinkID
). Las líneas 10 y 11 especifican que @LinkID
es un parámetro de tipo BigInt
. Ejecuto esta consulta más adelante en el ejemplo, en la línea 20.
La línea 13 obtiene un objeto Folder
que representa la carpeta indicada por el recurso compartido que especificó al crear el contexto. Las líneas 15 y 16 configuran el bucle para recorrer la colección de objetos Organization
de esta carpeta.
Para cada organización, la línea 17 obtiene el objeto EmployeeData
para el CEO.
La línea 19 se prepara para la consulta y establece el valor del parámetro en el LinkID adecuado y, a continuación, la línea 20 ejecuta el SELECT con parámetros.
La línea 21 lee la siguiente y solo fila del resultado de la consulta, y las líneas 22 y 23 imprimen el nombre del CEO y el salario medio de 10 años.
Resumen
El almacén de datos de WinFS proporciona un modelo de almacenamiento de datos mucho más completo que los sistemas de archivos tradicionales. Dado que admite datos, comportamiento y relaciones, es difícil clasificar WinFS como un sistema de archivos, una base de datos relacional o una base de datos de objetos. Es un poco de todas esas tecnologías en un producto. WinFS proporciona una definición común de información ubicua que es visible globalmente y disponible para todas las aplicaciones que se ejecutan en Longhorn. Las aplicaciones pueden aprovechar las funcionalidades de consulta, recuperación, actualización transaccional y filtrado de WinFS; por lo tanto, el desarrollador dedica menos tiempo a desarrollar el acceso a los datos y el código de almacenamiento y más tiempo trabajando en la funcionalidad de aplicación única.
continuar con el capítulo 5: de enlace de datos