¿Cuál es la forma más eficiente de asignar dos tipos de clave diferentes a una estructura?

En el código aquí, he creado un nuevo Cliente llamado "mcycleowner" y lo asigné a una dirección de entrada. Sin embargo, también quiero asignarlo a la entrada _license para que se pueda consultar la información del cliente con una dirección Eth o un número de matrícula.

Para hacerlo, creé un nuevo Cliente "mcyclelicenses", y la función addLicense toma las mismas entradas que newMcycleOwner (excepto la dirección), solo que este Cliente está asignado a _license. Esta función se activa dentro de la función "newMcycleOwner" para que tanto los clientes como las asignaciones se creen simultáneamente.

Sin embargo, hacerlo de esta manera significa tener dos registros de la información de cada cliente, lo que parece una pérdida de espacio, y también cada vez que se necesite cambiar la información del cliente, se tendrá que cambiar en dos lugares. ¿Hay una mejor manera de hacer esto?

// < ---------------------- MOTORCYLCES ---------------------- >


mapping (address => Customer) mcycleowners;
address[] public mcycleownerAdds;


function newMcycleOwner(address _address, string _custname, string _color, string _make, uint32 _year, string _license) onlyMember public {

    Customer storage mcycleowner = mcycleowners[_address];
        mcycleowner.custname = _custname;
        mcycleowner.color = _color;
        mcycleowner.make = _make;
        mcycleowner.year = _year;
        mcycleowner.license = _license;

        mcycleownerAdds.push(_address);

    addLicense(_custname, _color, _make, _year, _license);
}

    function getMcycleAdds() public view returns(address[]) {
        return mcycleownerAdds;
    }

    function getMcycleByAdd(address _address) public view returns(string, string) {
        return (mcycleowners[_address].custname, mcycleowners[_address].license);
    }

    function countMcycle() public view returns(uint) {
        return mcycleownerAdds.length;
    }


// <---------- CREATION OF NEW MAP SO WE CAN QUERY BY LICENSE ---------->

//This seems to create two instances of each customer.  Replace with a better method.

mapping (string => Customer) mcyclelicenses;

function addLicense(string _custname, string _color, string _make, uint32 _year, string _license) onlyMember public {
    Customer storage mcyclelicense = mcyclelicenses[_license];
        mcyclelicense.custname = _custname;
        mcyclelicense.color = _color;
        mcyclelicense.make = _make;
        mcyclelicense.year = _year;

}

 function getMcycleByLic(string _license) public view returns(string, string, string, uint32) {
    return (mcyclelicenses[_license].custname, mcyclelicenses[_license].color, mcyclelicenses[_license].make, mcyclelicenses[_license].year);
}

Respuestas (2)

Una manera fácil de hacerlo podría ser guardar la información de los clientes dentro de una matriz y usar la asignación para almacenar los índices de la matriz, de modo que acceda directamente al índice a través de la asignación y use este índice para acceder directamente a la matriz.

Aquí un ejemplo

pragma solidity ^0.4.23;

contract ContractX {
    struct Customer {
        string name;
        string license;
        /* other infos */
    }

    mapping (address => uint) addressIndexes;
    mapping (string => uint) licenseIndexes;
    Customer[] customers;
    uint customerCount;

    function addNewItem(address _address, string _name, string _license) public {
        customers.push(Customer(_name, _license));

        addressIndexes[_address] = customerCount;
        licenseIndexes[_license] = customerCount;

        customerCount++;
    }

    function getByAddress(address _address) public view returns(string, string) {
        return (
            customers[addressIndexes[_address]].name, 
            customers[addressIndexes[_address]].license
        );
    }

    function getByLicense(string _license) public view returns(string, string) {
        return (
            customers[licenseIndexes[_license]].name, 
            customers[licenseIndexes[_license]].license
        );
    }
}

Por lo tanto, la información del cliente se ha guardado solo una vez y solo realiza un seguimiento del índice de matriz en el mapeo para que pueda usarlo más tarde para acceder directamente al cliente que necesita.

Otra solución podría ser usar el Customercomo un subcontrato, luego crear el contrato cuando agregue la información de su cliente y almacenar la dirección de este nuevo contrato en sus asignaciones. Pero eso abre otro escenario, y es posible que deba realizar varios cambios.

Esto es genial. Siendo todavía bastante nuevo en Solidity, aún no me había dado cuenta de que podía devolver elementos específicos de una matriz (solo que podía devolver la matriz completa o la longitud de la matriz). Estaré probando esto. ¡Gracias!

Simplemente puede asignar la licencia a una dirección y luego hacer dos búsquedas para eliminar la referencia de una licencia.

mapping(string => address) mcyclelicences;

function getMcycleByLic(string _license) public view returns(string, string, string, uint32) { 
  return (
    mcycleowners[mcyclelicenses[_license]].custname,
    mcycleowners[mcyclelicenses[_license]].color,
    mcycleowners[mcyclelicenses[_license]].make,
    mcycleowners[mcyclelicenses[_license]].year
  );      
}
Esto es bastante interesante y parece ser un gran atajo. Probaré ambos pronto. ¡Gracias!